How do I safely generate a monotonically increasing sequence for use in e.g. generation a job number?

I have a use case where I need to generate a Job Number associated with many transactions in my app. How do I go about generating this Job Number that will not conflict with other users generating transactions in my app?

The best way to do this in JourneyApps without conflict is to use a CloudCode task that is limited to a single instance. This will ensure that the task never runs in multiple threads and only updates / increments the master job number.

![Configuration for a task that always runs in 1 thread only](upload://rOqdAtElIS7lmNqQqPOl0S5kogP.png)

You will notice from the photo that this task also has Webhooks enabled. This allows us to specify the model, e.g.: job that needs to trigger this task.

<model name="job" label="Job">
        <field name="number" label="Number" type="text:number" />
        <field name="timestamp" label="Timestamp" type="datetime" />

        <webhook type="ready" receiver="cloudcode" action="create_job_number" />

        <display>{number}</display> 
    </model>

Also, we will need a model with exactly 1 object in the DB to store our high water mark, rather than querying all jobs to find the next number:

 <model name="job_number" label="SYSTEM: Job Number High Water Mark">
        <field name="high_water_mark" label="High Water Mark" type="number" />
        <display>{high_water_mark:.0f}</display>
    </model>

And finally, the CloudCode code which will execute the task that increments the job number.

export async function run(params) {
    let eventObject = await params.object
    let _objectID = eventObject.id;
    let _object = await DB.job.first(_objectID);    
    let highWater = await DB.job_number.first();
    console.log(`High water mark ${highWater.high_water_mark}`)
    highWater.high_water_mark ++;
    console.log(`New high water mark ${highWater.high_water_mark}`);
    _object.job_number =   highWater.high_water_mark;
    await highWater.save();
    await _object.save();
}
4 Likes

This is a very innovative answer, well done. +1