@@ -26,7 +26,7 @@ class StartServer extends Command
2626 {--disable-statistics : Disable the statistics tracking.}
2727 {--statistics-interval= : The amount of seconds to tick between statistics saving.}
2828 {--debug : Forces the loggers to be enabled and thereby overriding the APP_DEBUG setting.}
29- {--test : Prepare the server, but do not start it .}
29+ {--loop : Programatically inject the loop .}
3030 ' ;
3131
3232 /**
@@ -79,6 +79,8 @@ public function handle()
7979
8080 $ this ->configureRoutes ();
8181
82+ $ this ->configurePcntlSignal ();
83+
8284 $ this ->startServer ();
8385 }
8486
@@ -156,6 +158,31 @@ protected function configureRoutes()
156158 WebSocketRouter::routes ();
157159 }
158160
161+ /**
162+ * Configure the PCNTL signals for soft shutdown.
163+ *
164+ * @return void
165+ */
166+ protected function configurePcntlSignal ()
167+ {
168+ // When the process receives a SIGTERM or a SIGINT
169+ // signal, it should mark the server as unavailable
170+ // to receive new connections, close the current connections,
171+ // then stopping the loop.
172+
173+ $ this ->loop ->addSignal (SIGTERM , function () {
174+ $ this ->line ('Closing existing connections... ' );
175+
176+ $ this ->triggerSoftShutdown ();
177+ });
178+
179+ $ this ->loop ->addSignal (SIGINT , function () {
180+ $ this ->line ('Closing existing connections... ' );
181+
182+ $ this ->triggerSoftShutdown ();
183+ });
184+ }
185+
159186 /**
160187 * Configure the HTTP logger class.
161188 *
@@ -209,14 +236,6 @@ protected function startServer()
209236
210237 $ this ->buildServer ();
211238
212- // For testing, just boot up the server, run it
213- // but exit after the next tick.
214- if ($ this ->option ('test ' )) {
215- $ this ->loop ->futureTick (function () {
216- $ this ->loop ->stop ();
217- });
218- }
219-
220239 $ this ->server ->run ();
221240 }
222241
@@ -231,6 +250,10 @@ protected function buildServer()
231250 $ this ->option ('host ' ), $ this ->option ('port ' )
232251 );
233252
253+ if ($ loop = $ this ->option ('loop ' )) {
254+ $ this ->loop = $ loop ;
255+ }
256+
234257 $ this ->server = $ this ->server
235258 ->setLoop ($ this ->loop )
236259 ->withRoutes (WebSocketRouter::getRoutes ())
@@ -249,4 +272,29 @@ protected function getLastRestart()
249272 'beyondcode:websockets:restart ' , 0
250273 );
251274 }
275+
276+ /**
277+ * Trigger a soft shutdown for the process.
278+ *
279+ * @return void
280+ */
281+ protected function triggerSoftShutdown ()
282+ {
283+ $ channelManager = $ this ->laravel ->make (ChannelManager::class);
284+
285+ // Close the new connections allowance on this server.
286+ $ channelManager ->declineNewConnections ();
287+
288+ // Get all local connections and close them. They will
289+ // be automatically be unsubscribed from all channels.
290+ $ channelManager ->getLocalConnections ()
291+ ->then (function ($ connections ) use ($ channelManager ) {
292+ foreach ($ connections as $ connection ) {
293+ $ connection ->close ();
294+ }
295+ })
296+ ->then (function () {
297+ $ this ->loop ->stop ();
298+ });
299+ }
252300}
0 commit comments