180180""" )
181181
182182
183- _GET_BEST_NODE = sqltext ("""\
183+ # MySQL: log(0) returns NULL, and NULLs sort first with ASC — zero-load
184+ # nodes naturally win. Original query unchanged.
185+ _GET_BEST_NODE_MYSQL = sqltext ("""\
184186 select
185187 id, node
186188from
192194 and downed = 0
193195 and backoff = 0
194196order by
195- log(GREATEST(current_load, 1)) / log(capacity)
197+ log(current_load) / log(capacity)
198+ limit 1
199+ """ )
200+
201+ # PostgreSQL: log(0) raises InvalidArgumentForLogarithm, so we use NULLIF
202+ # to convert zero to NULL explicitly. NULLS FIRST replicates MySQL's default
203+ # NULL-first ASC sort order, ensuring zero-load nodes are always preferred.
204+ _GET_BEST_NODE_POSTGRES = sqltext ("""\
205+ select
206+ id, node
207+ from
208+ nodes
209+ where
210+ service = :service
211+ and available > 0
212+ and capacity > current_load
213+ and downed = 0
214+ and backoff = 0
215+ order by
216+ log(NULLIF(current_load, 0)) / log(capacity) NULLS FIRST
196217limit 1
197218""" )
198219
@@ -656,8 +677,10 @@ def add_node(self, node, capacity, **kwds):
656677 capacity = capacity ,
657678 available = available ,
658679 current_load = kwds .get ("current_load" , 0 ),
659- downed = kwds .get ("downed" , 0 ),
660- backoff = kwds .get ("backoff" , 0 ),
680+ # Cast to int: optparse action="store_true" produces Python bools,
681+ # which postgres rejects for INTEGER columns (MySQL coerces silently).
682+ downed = int (kwds .get ("downed" , 0 )),
683+ backoff = int (kwds .get ("backoff" , 0 )),
661684 )
662685 res .close ()
663686
@@ -679,6 +702,11 @@ def update_node(self, node, **kwds):
679702 query += """
680703 where service = :service and node = :node
681704 """
705+ # Cast boolean fields to int: Python bools are rejected by postgres
706+ # INTEGER columns. MySQL coerces silently; postgres does not.
707+ for field in ("downed" , "backoff" ):
708+ if field in values :
709+ values [field ] = int (values [field ])
682710 values ["service" ] = self ._get_service_id (SERVICE_NAME )
683711 values ["node" ] = node
684712 if kwds :
@@ -750,8 +778,16 @@ def get_best_node(self):
750778 # capacity. This loop allows a maximum of five retries before
751779 # bailing out.
752780 for _ in range (5 ):
781+ # Select the appropriate query variant — postgres requires
782+ # explicit NULL handling for log(0) and NULL sort order that
783+ # MySQL handles implicitly.
784+ best_node_query = (
785+ _GET_BEST_NODE_POSTGRES
786+ if self .db_mode == "postgresql"
787+ else _GET_BEST_NODE_MYSQL
788+ )
753789 res = self ._execute_sql (
754- _GET_BEST_NODE , service = self ._get_service_id (SERVICE_NAME )
790+ best_node_query , service = self ._get_service_id (SERVICE_NAME )
755791 )
756792 row = res .fetchone ()
757793 res .close ()
0 commit comments