Search code examples
javaansiblecontinuous-integrationsystemd

Restrict restarting systemd service with timer assigned


I have a systemd service unit with OnCalendar timer assigned to it. That service invokes JVM, which runs code, that has to be started only on a specific schedule.

This systemd unit (and several others) are managed by the ansible playbook, which uses openstack/ansible-role-systemd_service role. It restarts systemd services every time I make some changes in their unit files.

Also, there's a handler, which restarts all the services every time Gitlab CI pipeline runs this ansible playbook and uploads a new .jar artifact to a server.

Is there any systemd built-in mechanism to restrict restarting service with timer assigned to it? Still, I have to be able to stop/start those services manually when it's needed.

Seems like I can fork that ansible role and add some check, but I wonder for some native and more straight-forward way to achieve this.


Solution

  • Seems I've found the way:

    Create and don't enable .service unit, that would contain next:

    [Unit]
    After = network-online.target
    ...
    
    [Service]
    Type = simple
    ...
    SuccessExitStatus = 143
    RestartForceExitStatus = 143
    Restart = on-failure
    RemainAfterExit = False
    StandardOutput = null
    StandardError = syslog
    
    [̶I̶n̶s̶t̶a̶l̶l̶]
    W̶a̶n̶t̶e̶d̶B̶y̶ ̶=̶ ̶m̶u̶l̶t̶i̶-̶u̶s̶e̶r̶.̶t̶a̶r̶g̶e̶t̶
    

    Create and enable .timer unit, that would contain next:

    [Timer]
    O̶n̶B̶o̶o̶t̶S̶e̶c̶ ̶=̶ ̶0̶m̶i̶n̶
    OnCalendar = *-*-* 18:00:00
    Persistent = yes
    
    [Install]
    WantedBy=multi-user.target
    

    A little explanation:

    After = network-online.target
    

    Needed to make sure that service would start only after getting online.

    Restart = on-failure
    SuccessExitStatus = 143
    RestartForceExitStatus = 143
    

    Needed to be able to kill the main process and make systemd restart the service, or stop the service w/o systemd marking it failed. It's because JVM returning 143 exit code when the main process receives SIGTERM and stops gracefully.

    RemainAfterExit = False  
    

    Needed for .timer to understand that .service stoped. Either way, .timer would hang in the running state, and won't run service next time.

    StandardOutput = null
    StandardError = syslog
    

    Needed to stop the main process from writing its INFO log to syslog, and write there only ERRORs.

    [̶I̶n̶s̶t̶a̶l̶l̶]
    W̶a̶n̶t̶e̶d̶B̶y̶ ̶=̶ ̶m̶u̶l̶t̶i̶-̶u̶s̶e̶r̶.̶t̶a̶r̶g̶e̶t̶
    

    Omitted cause the service has to be disabled. Either way, it would be stared on system boot.

    Persistent = yes
    

    Needed to be able to start service later that day after system boot, if the target time was missed.

    O̶n̶B̶o̶o̶t̶S̶e̶c̶ ̶=̶ ̶0̶m̶i̶n̶
    

    Omitted cause OnCalendar was used.

    All those changes seem to have done the trick.