Function: Synchronized()
Synchronized(
name,options?): (target,propertyKey,descriptor) =>PropertyDescriptor
Run a controller action holding a lock, acquired once its input is validated and its access control passed, released after it (whether it returns or throws). The requests needing the same lock run one at a time in every instance sharing the lock store, whatever their transport (HTTP, CLI, service); the others run in parallel.
The lock comes from the Mutex component registered as mutex (or options.mutex); a missing component fails the request. The wait for the lock stops when the request is aborted (its client gone), and a request not getting the lock in time fails with a MutexTimeoutException (HTTP 409). The action is not interrupted when its lock is lost: check the controller's this.signal for a long work.
Parameters
name
string | ((input, context) => string)
The lock name: a template filled from the fields of the action's input ('order:{id}', see lockNameOf; a missing field fails the request with a TypeError), or a function of the input and the request's context returning it.
options?
The lock component, the wait and the lock's ttl.
Returns
The method decorator.
(target, propertyKey, descriptor) => PropertyDescriptor
Throws
When the class is declared, if the name is neither a non-empty string nor a function, or if the decorated member is not a method.
Throws
From the action, when the lock is not acquired in time (HTTP 409).
Throws
From the action, when the lock store fails.
Example
import {Controller} from 'lakutata/com/entrypoint'
import {ServiceAction} from 'lakutata/decorator/ctrl'
import {Synchronized} from 'lakutata/com/mutex'
class OrderController extends Controller {
//The payments of an order one at a time, the other orders in parallel
@ServiceAction({cmd: 'order.pay'})
@Synchronized('order:{id}')
public async pay(input: {id: number}): Promise<void> {
}
//Fails at once (HTTP 409) while another request rebuilds the index
@ServiceAction({cmd: 'search.reindex'})
@Synchronized('search:reindex', {wait: false})
public async reindex(): Promise<void> {
}
//A lock named by a function, from the component registered as "locks"
@ServiceAction({cmd: 'user.export'})
@Synchronized((input: {userId: string}): string => `export:${input.userId}`, {timeout: 5000, mutex: 'locks'})
public async export(input: {userId: string}): Promise<void> {
}
}