The service life-cycle interface

Stopping the service

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.

  • SIGINT signal (equivalent to using <ctrl+c>)
  • SIGTERM signal
  • tomodachi.exit() or tomodachi.exit(exit_code)

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 tomodachi.SERVICE_EXIT_CODE.

Graceful shutdown

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.

Function hooks for service lifecycle changes

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 nameWhen is the function called?What is suitable to put here
_start_serviceCalled before invokers / servers have started.Initialize connections to databases, etc.
_started_serviceCalled after invokers / server have started.Start reporting or start tasks to run once.
_stopping_serviceCalled on termination signal.Cancel eventual internal long-running tasks.
_stop_serviceCalled 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.

    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.

    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.

    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.

Exceptions raised in _start_service or _started_service will gracefully terminate the service.