Stopping a service can be achieved by either sending a
SIGINT <ctrl+c> or
SIGTERM signal to to the
tomodachi Python process, or by invoking the
tomodachi.exit() function, which will initiate the termination processing flow. The
tomodachi.exit() call can additionally take an optional exit code as an argument, which otherwise will default to use exit code 0.
SIGINTsignal (equivalent to using <ctrl+c>)
The process' exit code can also be altered by changing the value of
tomodachi.SERVICE_EXIT_CODE, however using
tomodachi.exit with an integer argument will override any previous value set to
All above mentioned ways of initiating the termination flow of the service will perform a graceful shutdown of the service which will try to await open HTTP handlers and await currently running tasks using tomodachi's scheduling functionality as well as await tasks processing messages from queues such as AWS SQS or RabbitMQ.
Some tasks may timeout during termination according to used configuration (see options such as
http.termination_grace_period_seconds) if they are long running tasks. Additionally container handlers may impose additional timeouts for how long termination are allowed to take. If no ongoing tasks are to be awaited and the service lifecycle can be cleanly terminated the shutdown usually happens within milliseconds.
To be able to initialize connections to external resources or to perform graceful shutdown of connections made by a service, there's a few functions a service can specify to hook into lifecycle changes of a service.
|Magic function name||When is the function called?||What is suitable to put here|
|Called before invokers / servers have started.||Initialize connections to databases, etc.|
|Called after invokers / server have started.||Start reporting or start tasks to run once.|
|Called on termination signal.||Cancel eventual internal long-running tasks.|
|Called after tasks have gracefully finished.||Close connections to databases, etc.|
Changes to a service settings / configuration (by for example modifying the
options values) should be done in the
__init__ function instead of in any of the lifecycle function hooks.
Good practice – in general, make use of the
_start_service (for setting up connections) in addition to the
_stop_service (to close connections) lifecycle hooks. The other hooks may be used for more uncommon use-cases.
import tomodachi class Service(tomodachi.Service): name = "example" async def _start_service(self): # The _start_service function is called during initialization, # before consumers or an eventual HTTP server has started. # It's suitable to setup or connect to external resources here. return async def _started_service(self): # The _started_service function is called after invoker # functions have been set up and the service is up and running. # The service is ready to process messages and requests. return async def _stopping_service(self): # The _stopping_service function is called the moment the # service is instructed to terminate - usually this happens # when a termination signal is received by the service. # This hook can be used to cancel ongoing tasks or similar. # Note that some tasks may be processing during this time. return async def _stop_service(self): # Finally the _stop_service function is called after HTTP server, # scheduled functions and consumers have gracefully stopped. # Previously ongoing tasks have been awaited for completion. # This is the place to close connections to external services and # clean up eventual tasks you may have started previously. return
Exceptions raised in
_started_service will gracefully terminate the service.
Updated over 1 year ago