Decorators

Concurrency Decorators

Define TypeScript concurrency limits, locks, deduplication, throttling, debouncing, and idempotency semantics with AxilJS.

5 min readDocumentationEdit this page

Concurrency Decorators

AxilJS concurrency decorators describe how operations behave when multiple executions occur at the same time.

They express concurrency requirements as semantic metadata so a runtime or infrastructure consumer can implement locking, execution limits, request deduplication, throttling, debouncing, and idempotency without embedding those mechanics into business logic.

@tConcurrency

Defines a concurrency limit for an operation.

typescript
import { tConcurrency } from '@axiljs/decorator'
 
@tConcurrency({ limit: 10 })
async processOrders() {}

A named concurrency policy can be shared across operations:

typescript
@tConcurrency({
  name: 'order-processing',
  limit: 20,
})
async processOrder(orderId: string) {}

The consumer can use this metadata to control how many instances of the operation may execute concurrently.

@tLock

Declares that an operation requires a lock before execution.

typescript
import { tLock } from '@axiljs/decorator'
 
@tLock({ key: 'account:{accountId}' })
async updateBalance(accountId: string, amount: number) {}

The lock key can represent the resource whose concurrent modification must be coordinated.

For example:

typescript
@tLock({
  key: 'inventory:{productId}',
})
async reserveInventory(productId: string, quantity: number) {}

A lock-aware consumer can resolve the key and coordinate concurrent executions against the same resource.

@tMutex

Declares mutually exclusive execution for an operation or resource.

typescript
import { tMutex } from '@axiljs/decorator'
 
@tMutex('account-update')
async updateAccount(accountId: string) {}

Only one execution associated with the mutex can proceed at a time.

This is useful when concurrent execution could produce inconsistent state or violate an application invariant.

@tDedupe

Declares that equivalent concurrent requests should be deduplicated.

typescript
import { tDedupe } from '@axiljs/decorator'
 
@tDedupe({
  key: 'user:{userId}',
})
async loadUser(userId: string) {}

When multiple requests resolve to the same deduplication key, a concurrency-aware consumer can coalesce them instead of executing the same operation repeatedly.

This is particularly useful for high-frequency reads, expensive computations, and cache-miss protection.

@tThrottle

Limits how frequently an operation can execute.

typescript
import { tThrottle } from '@axiljs/decorator'
 
@tThrottle({
  limit: 100,
  window: 60_000,
})
async sendNotification() {}

The example allows up to 100 executions within a 60-second window.

Throttling is useful for protecting external APIs, shared resources, and internal services from excessive execution rates.

@tDebounce

Delays execution until activity has stopped for a configured period.

typescript
import { tDebounce } from '@axiljs/decorator'
 
@tDebounce(500)
async updateSearchIndex(query: string) {}

A debounce policy is useful when many events can arrive in rapid succession and only the latest execution is relevant.

Typical use cases include search indexing, event aggregation, and rapid state updates.

@tIdempotent

Declares that repeated execution with the same semantic request should produce an equivalent result rather than applying the operation multiple times.

typescript
import { tIdempotent } from '@axiljs/decorator'
 
@tIdempotent({
  key: 'payment:{paymentId}',
})
async processPayment(paymentId: string) {}

Idempotency is particularly important for distributed systems where a request may be retried because of network failures, timeouts, or message redelivery.

The decorator describes the requirement; an infrastructure consumer can implement mechanisms such as idempotency keys or persisted execution records.

Composing Concurrency Semantics

Concurrency decorators can be combined when an operation has multiple execution constraints.

typescript
import {
  tConcurrency,
  tLock,
  tIdempotent,
  tThrottle,
} from '@axiljs/decorator'
 
@tConcurrency({
  name: 'payment-processing',
  limit: 20,
})
@tLock({
  key: 'payment:{paymentId}',
})
@tIdempotent({
  key: 'payment:{paymentId}',
})
@tThrottle({
  limit: 100,
  window: 60_000,
})
async processPayment(paymentId: string) {
  return this.paymentService.process(paymentId)
}

The metadata describes several independent requirements:

  • Limit the number of concurrent executions.
  • Coordinate access to the same payment resource.
  • Prevent duplicate processing.
  • Limit the overall execution rate.

The runtime can interpret each semantic requirement through the appropriate concurrency infrastructure.

Concurrency and Distributed Systems

Concurrency control becomes more important when an operation can execute across multiple application instances.

A local in-memory lock may only coordinate executions inside one process. A distributed consumer may instead implement the same semantic requirement using infrastructure such as a distributed lock, shared state store, or coordination service.

For example:

typescript
@tLock({
  key: 'inventory:{productId}',
})
async reserveInventory(
  productId: string,
  quantity: number,
) {
  // Business operation
}

The business operation does not need to know whether the lock is implemented locally, through Redis, or through another coordination mechanism.

The decorator declares the invariant; the infrastructure layer determines how that invariant is enforced.

Concurrency Decorator Reference

DecoratorPurpose
@tConcurrencyLimits concurrent executions
@tLockDeclares a resource-level locking requirement
@tMutexDeclares mutually exclusive execution
@tDedupeCoalesces equivalent concurrent executions
@tThrottleLimits execution frequency
@tDebounceDelays execution until activity settles
@tIdempotentDeclares safe repeated execution semantics

Design Principle

Concurrency decorators should describe execution semantics rather than contain concurrency implementation.

For example:

typescript
@tIdempotent({
  key: 'payment:{paymentId}',
})
async processPayment(paymentId: string) {}

The method remains focused on the payment operation. The decorator communicates an important distributed-system requirement to the infrastructure consumer.

This keeps locking, deduplication, rate control, and idempotency mechanisms outside the business logic while keeping their policies visible at the operation boundary.

Help improve the documentation

AxilJS is open source and documentation improvements are welcome.

AxilJS DocumentationMIT License · Built by SyntaxilitY