@@ -30,6 +30,9 @@ def subscribe(self, channel):
30
30
def unsubscribe (self , channel ):
31
31
raise NotImplementedError ()
32
32
33
+ def get_subscriptions (self ):
34
+ raise NotImplementedError ()
35
+
33
36
@classmethod
34
37
def publish (cls , channel , payload = None ):
35
38
raise NotImplementedError ()
@@ -57,35 +60,35 @@ def drain_non_blocking_fd(fd):
57
60
os .read (fd , 256 )
58
61
59
62
60
- PID = os .getpid ()
61
-
62
-
63
63
class PostgresPubSub (BasePubSubBackend ):
64
+ PID = os .getpid ()
64
65
65
66
def __init__ (self ):
66
67
self ._subscriptions = set ()
67
68
self .message_buffer = []
68
- self .cursor = connection .cursor ()
69
+ # ensures a connection is initialized
70
+ with connection .cursor () as cursor :
71
+ cursor .execute ("select 1" )
69
72
self .backend_pid = connection .connection .info .backend_pid
70
- # logger.info(f"{connection.connection.info.backend_pid=}")
71
73
self .sentinel_r , self .sentinel_w = os .pipe ()
72
74
os .set_blocking (self .sentinel_r , False )
73
75
os .set_blocking (self .sentinel_w , False )
74
76
connection .connection .add_notify_handler (self ._store_messages )
75
77
78
+ @classmethod
79
+ def _debug (cls , message ):
80
+ logger .debug (f"[{ cls .PID } ] { message } " )
81
+
76
82
def _store_messages (self , notification ):
77
- # logger.info(f"[{PID}] Received message: {notification}")
78
83
self .message_buffer .append (
79
84
PubsubMessage (channel = notification .channel , payload = notification .payload )
80
85
)
81
86
if notification .pid == self .backend_pid :
82
87
os .write (self .sentinel_w , b"1" )
83
-
84
- def get_subscriptions (self ):
85
- return self ._subscriptions .copy ()
88
+ self ._debug (f"Received message: { notification } " )
86
89
87
90
@classmethod
88
- def publish (cls , channel , payload = None ):
91
+ def publish (cls , channel , payload = "" ):
89
92
query = (
90
93
(f"NOTIFY { channel } " ,)
91
94
if not payload
@@ -94,6 +97,7 @@ def publish(cls, channel, payload=None):
94
97
95
98
with connection .cursor () as cursor :
96
99
cursor .execute (* query )
100
+ cls ._debug (f"Sent message: ({ channel } , { str (payload )} )" )
97
101
98
102
def subscribe (self , channel ):
99
103
self ._subscriptions .add (channel )
@@ -108,7 +112,12 @@ def unsubscribe(self, channel):
108
112
with connection .cursor () as cursor :
109
113
cursor .execute (f"UNLISTEN { channel } " )
110
114
115
+ def get_subscriptions (self ):
116
+ return self ._subscriptions .copy ()
117
+
111
118
def fileno (self ) -> int :
119
+ # when pub/sub clients are the same, the notification callback may be called
120
+ # asynchronously, making select on connection miss new notifications
112
121
ready , _ , _ = select .select ([self .sentinel_r ], [], [], 0 )
113
122
if self .sentinel_r in ready :
114
123
return self .sentinel_r
@@ -120,7 +129,7 @@ def fetch(self) -> list[PubsubMessage]:
120
129
result = self .message_buffer .copy ()
121
130
self .message_buffer .clear ()
122
131
drain_non_blocking_fd (self .sentinel_r )
123
- # logger.info (f"[{PID}] Fetched messages: {result}")
132
+ self . _debug (f"Fetched messages: { result } " )
124
133
return result
125
134
126
135
def close (self ):
0 commit comments