Ubuntu – How to create a single-execution Upstart job guaranteed to complete before two other jobs begin

eventsinitscriptsstartupupstart

How does one write an Upstart task that is guaranteed to run only once after each startup but is also guaranteed to run to completion before either one of at least two other jobs start running. I do not want to alter the Upstart init files for those two other jobs as they do not belong to me. Restarting either of those two other jobs should not cause the desired task to run again.

The situation is that the desired task must make some modifications to some files in the local filesystem that both of the other jobs will be needing.

I'm completely new to Upstart and finding it a steeper learning curve than I'd expected, so an education on why the solution works will be as valuable as the solution itself.

Best Answer

  • I believe I have an answer to my own question that leverages CameronNemo's partial solution and Mark Russell's answer to a related but somewhat different question.

    Two Upstart configuration files are required. The first is a job that starts as soon as the local filesystem is available, performs the desired file modifications as a pre-start script, and then sits idle in the running state forever:

    # modify-files - Single-execution file modification job
    
    start on local-filesystems
    
    console log
    
    pre-start script
      echo "$(date --rfc-3339=ns) $(hostname) $UPSTART_JOB"
      exec /path/to/your/script
    end script
    

    The second configuration file is an Upstart task that delays the start of all other jobs that might depend on the files we're trying to modify. It produces one instance of itself per dependent job:

    # modify-files-wait - Helper task for modify-files
    
    start on (starting jobA or jobB)
    stop on (started modify-files or stopped modify-files)
    
    instance $JOB
    
    console log
    normal exit 0 2
    task
    
    script
      echo "$(date --rfc-3339=ns) $(hostname) $UPSTART_JOB ($UPSTART_INSTANCE)"
      status modify-files | grep -q "start/running" && exit 0
      start modify-files || true
      sleep infinity
    end script
    

    Upstart will kill all instances of modify-files-wait once modify-files is idling in its running state. That normal exit line accounts for the possibility of being killed during its infinite sleep. We need the task line to block jobA and joB until the stopped state is reached. Whichever instance runs first will start modify-files, if it hasn't already been started.

    Since modify-files never reaches its stopped state, it will never be run anew, regardless of jobA or jobB being restarted.

    This solution seems to be working, but I welcome any criticisms or improvements.