@@ -78,6 +78,12 @@ type NatsAPI struct {
7878 jobCh chan natsMessage
7979 // nodeCh receives node state messages for processing by worker goroutines.
8080 nodeCh chan natsMessage
81+ // stop signals worker goroutines and subscription callbacks to stop.
82+ // Closing it (via Shutdown) makes workers exit and callbacks drop further
83+ // messages instead of blocking; the channels are never closed so in-flight
84+ // callbacks can never send on a closed channel.
85+ stop chan struct {}
86+ stopOnce sync.Once
8187}
8288
8389// NewNatsAPI creates a new NatsAPI instance with channel-based worker pools.
@@ -99,6 +105,7 @@ func NewNatsAPI() *NatsAPI {
99105 JobRepository : repository .GetJobRepository (),
100106 jobCh : make (chan natsMessage , jobConc ),
101107 nodeCh : make (chan natsMessage , nodeConc ),
108+ stop : make (chan struct {}),
102109 }
103110
104111 // Start worker goroutines
@@ -112,17 +119,36 @@ func NewNatsAPI() *NatsAPI {
112119 return api
113120}
114121
122+ // Shutdown stops the worker goroutines and tells subscription callbacks to stop
123+ // enqueueing. It is safe to call multiple times. Callers must ensure the NATS
124+ // client is closed first so no new callbacks are invoked.
125+ func (api * NatsAPI ) Shutdown () {
126+ api .stopOnce .Do (func () {
127+ close (api .stop )
128+ })
129+ }
130+
115131// jobWorker processes job event messages from the job channel.
116132func (api * NatsAPI ) jobWorker () {
117- for msg := range api .jobCh {
118- api .handleJobEvent (msg .subject , msg .data )
133+ for {
134+ select {
135+ case <- api .stop :
136+ return
137+ case msg := <- api .jobCh :
138+ api .handleJobEvent (msg .subject , msg .data )
139+ }
119140 }
120141}
121142
122143// nodeWorker processes node state messages from the node channel.
123144func (api * NatsAPI ) nodeWorker () {
124- for msg := range api .nodeCh {
125- api .handleNodeState (msg .subject , msg .data )
145+ for {
146+ select {
147+ case <- api .stop :
148+ return
149+ case msg := <- api .nodeCh :
150+ api .handleNodeState (msg .subject , msg .data )
151+ }
126152 }
127153}
128154
@@ -140,13 +166,19 @@ func (api *NatsAPI) StartSubscriptions() error {
140166 s := config .Keys .APISubjects
141167
142168 if err := client .Subscribe (s .SubjectJobEvent , func (subject string , data []byte ) {
143- api .jobCh <- natsMessage {subject : subject , data : data }
169+ select {
170+ case api .jobCh <- natsMessage {subject : subject , data : data }:
171+ case <- api .stop :
172+ }
144173 }); err != nil {
145174 return err
146175 }
147176
148177 if err := client .Subscribe (s .SubjectNodeState , func (subject string , data []byte ) {
149- api .nodeCh <- natsMessage {subject : subject , data : data }
178+ select {
179+ case api .nodeCh <- natsMessage {subject : subject , data : data }:
180+ case <- api .stop :
181+ }
150182 }); err != nil {
151183 return err
152184 }
0 commit comments