55import java .sql .Statement ;
66import java .util .Map ;
77import java .util .concurrent .ConcurrentHashMap ;
8+ import java .util .concurrent .atomic .AtomicReference ;
89import java .util .concurrent .locks .Condition ;
910import java .util .concurrent .locks .ReentrantLock ;
1011
@@ -25,8 +26,7 @@ public static class LockConditionPair {
2526 private static final Logger logger = LoggerFactory .getLogger (NotificationService .class );
2627
2728 private final Map <String , LockConditionPair > notificationsMap = new ConcurrentHashMap <>();
28- private volatile boolean running = false ;
29- private Thread notificationListenerThread ;
29+ private final AtomicReference <Thread > notificationListenerThread = new AtomicReference <>(null );
3030 private final DataSource dataSource ;
3131
3232 public NotificationService (DataSource dataSource ) {
@@ -46,21 +46,20 @@ public void unregisterNotificationCondition(String key) {
4646 }
4747
4848 public void start () {
49- if (!running ) {
50- running = true ;
51- notificationListenerThread = new Thread (this ::notificationListener , "NotificationListener" );
52- notificationListenerThread .setDaemon (true );
53- notificationListenerThread .start ();
49+ Thread t = new Thread (this ::notificationListener , "NotificationListener" );
50+ t .setDaemon (true );
51+ if (notificationListenerThread .compareAndSet (null , t )) {
52+ t .start ();
5453 logger .debug ("Notification listener started" );
5554 }
5655 }
5756
5857 public void stop () {
59- running = false ;
60- if (notificationListenerThread != null ) {
61- notificationListenerThread .interrupt ();
58+ Thread t = notificationListenerThread . getAndSet ( null ) ;
59+ if (t != null ) {
60+ t .interrupt ();
6261 try {
63- notificationListenerThread .join (5000 ); // Wait up to 5 seconds
62+ t .join (5000 ); // Wait up to 5 seconds
6463 } catch (InterruptedException e ) {
6564 Thread .currentThread ().interrupt ();
6665 }
@@ -71,7 +70,7 @@ public void stop() {
7170 }
7271
7372 private void notificationListener () {
74- while (running ) {
73+ while (notificationListenerThread . get () == Thread . currentThread () ) {
7574 Connection notificationConnection = null ;
7675
7776 try {
@@ -89,11 +88,9 @@ private void notificationListener() {
8988
9089 logger .debug ("Listening for PostgreSQL notifications" );
9190
92- while (running ) {
93- // Check for notifications with a timeout
94- PGNotification [] notifications = pgConnection .getNotifications (1000 ); // 1
95- // second
96- // timeout
91+ while (notificationListenerThread .get () == Thread .currentThread ()) {
92+ // Check for notifications with a one second timeout
93+ PGNotification [] notifications = pgConnection .getNotifications (1000 );
9794
9895 if (notifications != null ) {
9996 for (PGNotification notification : notifications ) {
@@ -102,19 +99,21 @@ private void notificationListener() {
10299
103100 logger .debug ("Received notification on channel: {}, payload: {}" , channel , payload );
104101
105- if ("dbos_notifications_channel" .equals (channel )) {
106- handleNotification (payload , "notifications" );
107- } else if ("dbos_workflow_events_channel" .equals (channel )) {
108- handleNotification (payload , "workflow_events" );
109- } else {
110- logger .error ("Unknown NOTIFY channel: {}" , channel );
111- }
102+ if (null == channel ) {
103+ logger .error ("Received notification with null channel. Payload: {}" , payload );
104+ } else
105+ switch (channel ) {
106+ case "dbos_notifications_channel" -> handleNotification (payload , "notifications" );
107+ case "dbos_workflow_events_channel" ->
108+ handleNotification (payload , "workflow_events" );
109+ default -> logger .error ("Unknown NOTIFY channel: {}" , channel );
110+ }
112111 }
113112 }
114113 }
115114
116115 } catch (Exception e ) {
117- if (running ) {
116+ if (notificationListenerThread . get () == Thread . currentThread () ) {
118117 logger .warn ("Notification listener error: {}" , e .getMessage ());
119118 try {
120119 Thread .sleep (1000 ); // Wait before retrying
0 commit comments