The Lino Daemon with django-channels, an extension to the notification framework

This document explains why and how to configure a lino daemon process and also the capabilities of the lino.modlib.linod plugin.

A Lino application can declare background tasks. Such tasks run in the background, i.e. as a service in another process than the web server. That other process listens over channel protocol (provided by django-channels).

runworker linod_myprj

Starts a long-running process that by default only listens for immediate desktop notifications which it sends when found.

It also has the capabilities to run scheduled jobs and logging non-lino log entries. Run the following command to enable these functionalities.

$ python initiate_linod

On a development machine you simply run these commands in separate terminals. On a production server we recommend to run this as a daemon via Supervisor as described below.

This feature requires redis and the following python packages to be installed: django-channels, channels_redis, schedule.

As an application developer you define background tasks using dd.schedule_often and dd.schedule_daily. For example the send_pending_emails_often and clear_seen_messages of the lino.modlib.notify plugin.


To enable this feature, you must set use_linod to True. This is usually done by the application developer, but this decision can be overridden by a system admin in a local file.


Additionally to having use_linod set to True, you must also set the supervisor configurations by doing configure_linod and restart supervisor using the command with sudo or root privilege:

$ service supervisor restart

The getlino configure --linod option specifies that every new Lino site will automatically configure a lino daemon process in the supervisor as a service.

Activating the feature

>>> from atelier.sheller import Sheller
>>> shell = Sheller("lino_book/projects/roger")
>>> shell("python linod --list")
This site does not use linod.

As a site maintainer you can check whether your application has scheduled background jobs by issuing the following command in your project directory:

$ python linod --list

For example in the noi1e demo project there are 6 jobs:

>>> shell = Sheller("lino_book/projects/noi1e")
>>> shell("python linod --list")
6 scheduled jobs:
[1] Every 1 day at 20:00:00 do checksummaries() (last run: [never], next run: ...)
[2] Every 1 day at 20:00:00 do checkdata() (last run: [never], next run: ...)
[3] Every 10 seconds do send_pending_emails_often() (last run: [never], next run: ...)
[4] Every 1 day at 20:00:00 do send_pending_emails_daily() (last run: [never], next run: ...)
[5] Every 1 day at 20:00:00 do clear_seen_messages() (last run: [never], next run: ...)
[6] Every 3600 seconds do update_all_repos() (last run: [never], next run: ...)

Installation instructions

This section has become useless because these things are now done automatically by getlino.

  • Install the Supervisor package:

    $ sudo apt install supervisor

    The supervisor package is being installed system-wide, it is not related to any specific project.

  • Create a file linod_myprj.conf in /etc/supervisor/conf.d/ with this content (given the context provided below):

    command=/bin/bash -c "source {{env_activate}} && python runworker {{channels}}"
    username = www-data
    umask = 002
    command=/bin/bash -c "source {{env_activate}} && python initiate_linod"
    username = www-data
    umask = 002
  • Context to fill out the above template (a dictionary mapping with example and a comment as description):

        'project_name': "myprj", # The name of your project
        'settings_module': "settings", # If you have a in your project's directory
        'project_path': "~/lino/lino_local/myprj", # The path at which your project is located
        'env_activate': "~/lino/lino_local/myprj/env/bin/activate", # The path to the binary that activates your project's python virtual environment
        'channels': "linod_myprj", # The name for linod with the prefix 'linod_' and your project name as the suffix, you can also add any additional channels.consumer.${"Sync"|"Async"}Consumer subclasses separated by a whitespace
  • Restart supervisord:

    $ sudo service supervisor restart
  • Have a look at the log files in /var/log/supervisor.