Process synchronisation/coordination

Hi,

I'd like to know if see if processes can be synchronised, with one instance waiting for another to release a lock, akin to the Java synchronized keyword or semaphore/mutexes. I know that process instances can be serialised when called from a single subprocess, but that is not quite the problem we have.

The scenario is that we have multiple process models calling a single re-usable subprocess. However, that subprocess cannot support multiple instances. The reason for this is the work it is doing. It is an integration service that links to our RPA environment. This subprocess does three things

  1. Login into the RPA platform and obtain an authentication token.
  2. Run a query to extract the list of queues on the platform to determine the identifier of the queue we want to target.
  3. Place a piece of data onto a data into the queue referenced by it's identifier.

This subprocess works, however, the RPA platform only allows a single login at a time. That means the login at step 1 invalidates all other tokens in use by the user. Therefore, if two of these subprocesses start (from the same or different main processes), the first will login, proceed to step 2, the second will login and invalidate the token of the first. Step 3 of the first process will then fail.

We don't have time-control over the processes in question as they are started from both timers and ad-hoc processes. Hence I was thinking to find some kind of waiting lock and unlock.

We've explored some ideas already, but nearly all have downsides:

  1. Locking a database record is a bit tricky here as it that can work if pessimistic locking is used, however this introduces a polling mechanism as it does not wait. Optimistic locking won't work as that takes a copy of the data and compares after, so allows the process to proceed.
  2. Locking a default document might work, but is a bit messy and potentially introduces a polling mechanism.
  3. Checking for other process instances of the same type can work, but has a race condition.
  4. Storing the token in the database can also work, so that each processes uses the same token, but there's still a race condition of the initial login, and timeout/expiry of the token becomes a problem to deal with.

I'm not sure if any of the message passing can help with this.

Thanks in advance,
Tim

  Discussion posts and replies are publicly visible

  • So, yes, you could synchronise in a number of different ways, depending on what the acceptable impacts are:

    • you could explicitly serialise the process models i.e. make them run in a sequence, so there's no possibility of them running the sub-process concurrently
    • you can (!) send messages between processes. So a process can be paused using a rule event (e.g. the rule event is looking at a Boolean flag that is defaulted to false). Then the process that completes sends a message to the process that is paused and sets that Boolean flag to true and resumes the paused process (messaging events should be used with caution as they have a performance overhead)
    • you can use a database table to hold a token that each process can poll for and get (and lock) when it is free to use. Personally I hate polling patterns with a vengeance as they absolutely do not scale, but it is an option
  • You can easily implement a queue in Appian which uses a process report, sorted by process start time, to determine whether the current instance is the top most. If not, loop back to a timer and try again later. Did that a few times, works great.

  • Hi,

    Thanks for the suggestions everyone. In the end, we used the Appan "increment constant" smart service. We basically set a constant to zero, then incremented it by 1 to lock. If the value returned from the increment constant is greater than one, then it does a retry backoff loop. At the end of the process it increments a constant by -1. This creates a mutex around the whole process. It's not the cleanest because we had to introduce a polling loop, but it does an incremental backoff by delaying until

    now() + intervalds(0,0, (pv!pvRetry*10) + (tointeger(rand() * 10)) )

    This is the process.

  • It's a nice compromise as your polling isn't across the Network (which I always picture as a whole crowd of people shouting across a noisy room "Is there any work for me to do?", which you can imagine simply doesn't scale very well!)