-
-
Notifications
You must be signed in to change notification settings - Fork 1
PostgreSQL Logical Replication Load-Balancing Example #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ddff950
dcc4b34
337a478
d9b0ce0
8503e66
5692699
054b108
70a08d6
1f0da9c
bc2cacd
34c7f62
75b90c4
3676b5f
6af53de
d5d8c05
ee47dcd
74a442e
acdcb34
81999a1
f3c316a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| class_mapping = { | ||
| 'System': 'System', | ||
| 'NetworkTopology': 'NetworkTopology', | ||
| 'NetIPv4': 'NetIPv4', | ||
| 'NetIPv6': 'NetIPv6', | ||
| 'HostNode': 'HostNode', | ||
| 'Database': 'Database', | ||
| 'Table': 'Table', | ||
| 'Column': 'Column' | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| references = { | ||
| 'UpdateNetworkTopology': { | ||
| 'System': { | ||
| 'property_ref': 'System', | ||
| 'children': { | ||
| 'NetworkTopology': { | ||
| 'property_ref': 'NetworkTopology', | ||
| 'children': { | ||
| 'NetIPv4': { | ||
| 'property_ref': 'NetIPv4' | ||
| }, | ||
| 'NetIPv6': { | ||
| 'property_ref': 'NetIPv6' | ||
| }, | ||
| 'HostNode': { | ||
| 'property_ref': 'HostNode' | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| 'InitDatabase': { | ||
| 'Database': { | ||
| 'property_ref': 'Database' | ||
| } | ||
| }, | ||
| 'CreateReplicaTable': { | ||
| 'Database': { | ||
| 'property_ref': 'Database', | ||
| 'children': { | ||
| 'Table': { | ||
| 'property_ref': 'Table', | ||
| 'children': { | ||
| 'Column': { | ||
| 'property_ref': 'Column' | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import_classes = { | ||
| 'service_implementation': [ | ||
| 'System', | ||
| 'NetworkTopology', | ||
| 'NetIPv4', | ||
| 'NetIPv6', | ||
| 'HostNode', | ||
| 'Database', | ||
| 'Table', | ||
| 'Column' | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,53 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import jsocket | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| from microesb import microesb | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| from class_reference import references as class_reference | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from service_properties import service_properties | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from class_mapping import class_mapping | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| logging.getLogger().addHandler( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logging.StreamHandler(sys.stdout) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| logging.getLogger().setLevel( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logging.DEBUG | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_current_ip_address(): | ||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd_get_ip = 'ip -h addr show dev eth0 | grep inet | cut -d " " -f 6' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| res = subprocess.run(cmd_get_ip, shell=True, capture_output=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| raw_ip = res.stdout.strip() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| raw_ip_sep = raw_ip.find(b'/') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return raw_ip[:raw_ip_sep] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+22
to
+26
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd_get_ip = 'ip -h addr show dev eth0 | grep inet | cut -d " " -f 6' | |
| res = subprocess.run(cmd_get_ip, shell=True, capture_output=True) | |
| raw_ip = res.stdout.strip() | |
| raw_ip_sep = raw_ip.find(b'/') | |
| return raw_ip[:raw_ip_sep] | |
| # Run `ip` directly without using a shell and parse the output in Python | |
| res = subprocess.run( | |
| ['ip', '-h', 'addr', 'show', 'dev', 'eth0'], | |
| capture_output=True, | |
| text=True | |
| ) | |
| ip_address = None | |
| for line in res.stdout.splitlines(): | |
| line = line.strip() | |
| if line.startswith('inet '): | |
| # The second field is the address with prefix, e.g. "192.168.0.10/24" | |
| parts = line.split() | |
| if len(parts) > 1: | |
| ip_with_prefix = parts[1] | |
| ip_address = ip_with_prefix.split('/')[0] | |
| break | |
| if ip_address is None: | |
| return b'' | |
| return ip_address.encode() |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,68 @@ | ||||||||||
| import abc | ||||||||||
| import logging | ||||||||||
| import datetime | ||||||||||
|
Comment on lines
+1
to
+3
|
||||||||||
| import abc | |
| import logging | |
| import datetime | |
| import logging |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'logger' variable is created but never used in this file. Either use it for logging within the class methods or remove this line to avoid confusion.
| logger = logging.getLogger(__name__) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| service_properties = { | ||
| 'System': { | ||
| 'properties': { | ||
| 'id': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'System id' | ||
| } | ||
| }, | ||
| 'methods': [ | ||
| 'update_network_topology' | ||
| ] | ||
| }, | ||
| 'NetworkTopology': { | ||
| 'properties': { | ||
| 'type': { | ||
| 'type': 'str', | ||
| 'default': 'un-partitioned', | ||
| 'required': False, | ||
| 'description': 'Network topology type' | ||
| } | ||
| } | ||
| }, | ||
| 'NetIPv4': { | ||
| 'properties': { | ||
| 'subnet': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'IPv4 subnet' | ||
| }, | ||
| 'netmask': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'IPv4 netmask' | ||
| }, | ||
| 'netbits': { | ||
| 'type': 'int', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'IPv4 netmask bits' | ||
| }, | ||
| 'gateway': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'IPv4 gateway address' | ||
| }, | ||
| 'hostaddress': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': False, | ||
| 'description': 'IPv4 docker host address' | ||
| } | ||
| } | ||
| }, | ||
| 'NetIPv6': { | ||
| 'properties': { | ||
| } | ||
| }, | ||
| 'HostNode': { | ||
| 'properties': { | ||
| 'name': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'Hostname' | ||
| }, | ||
| 'ipv4': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': False, | ||
| 'description': 'IPv4 address' | ||
| }, | ||
| 'ipv6': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': False, | ||
| 'description': 'IPv6 address' | ||
| } | ||
| } | ||
| }, | ||
| 'Database': { | ||
| 'properties': { | ||
| 'id': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'Database id' | ||
| } | ||
| }, | ||
| 'methods': [ | ||
| 'init_db', | ||
| 'create_replica_table' | ||
| ] | ||
| }, | ||
| 'Table': { | ||
| 'properties': { | ||
| 'name': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'Table name' | ||
| }, | ||
| 'add_timestamp_cols': { | ||
| 'type': 'bool', | ||
| 'default': True, | ||
| 'required': False, | ||
| 'description': 'Automatically add timestamp columns for insert and update' | ||
| }, | ||
| 'attach_replication_trigger': { | ||
| 'type': 'bool', | ||
| 'default': True, | ||
| 'required': False, | ||
| 'description': 'Automatically attach replication check trigger (currently only update)' | ||
| }, | ||
| } | ||
| }, | ||
| 'Column': { | ||
| 'properties': { | ||
| 'primary_key': { | ||
| 'type': 'bool', | ||
| 'default': False, | ||
| 'required': False, | ||
| 'description': 'Column primary key flag' | ||
| }, | ||
| 'name': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'Column id' | ||
| }, | ||
| 'type': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': True, | ||
| 'description': 'Column type' | ||
| }, | ||
| 'default': { | ||
| 'type': 'str', | ||
| 'default': None, | ||
| 'required': False, | ||
| 'description': 'Column default value' | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| #!/bin/sh | ||
| cd /json-rpc-server && python3 ./json-rpc-server.py & |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| FROM postgres:18-bookworm | ||
| MAINTAINER Claus Prüfer | ||
|
|
||
| RUN apt-get -qq update -y | ||
| RUN apt-get -qq install iproute2 iputils-ping net-tools python3-pip python3-psycopg2 -y | ||
|
|
||
| COPY ./packages/jsocket-1.9.5.tar.gz / | ||
|
|
||
| RUN pip3 install microesb --break-system-packages | ||
| RUN pip3 install ./jsocket-1.9.5.tar.gz --break-system-packages | ||
|
|
||
| RUN mkdir /json-rpc-server | ||
| COPY ./db-node-rpc/*.py /json-rpc-server/ | ||
| COPY ./db-node-rpc/*.sh /json-rpc-server/ | ||
|
|
||
| ENV POSTGRES_USER postgres | ||
clauspruefer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ENV POSTGRES_PASSWORD password | ||
| ENV POSTGRES_DB lb-test | ||
|
|
||
| EXPOSE 5432 | ||
| EXPOSE 64000 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #!/bin/sh | ||
|
|
||
| # build docker database node | ||
| docker build -t db-node --file ./db-node.dockerfile . |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "iptables": false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| #!/bin/sh | ||
|
|
||
| docker network create --subnet=172.16.1.0/24 --gateway=172.16.1.254 -o com.docker.network.bridge.enable_ip_masquerade=false -o com.docker.network.bridge.name=dbr0 dbpool-net |
Uh oh!
There was an error while loading. Please reload this page.