Semaphore Plugins
withSemaphorePrefix plugin
The Semaphore prefix plugin intercepts calls to a semaphore adapter and transparently prefixes all semaphore keys with a configurable string. This enables logical key namespacing without modifying the adapter implementation.
Use cases
- Multi-tenant semaphores — Prefix semaphore keys with a tenant identifier to isolate concurrency limits between tenants
- Resource scoping — Organize semaphores by resource type to avoid key collisions
- Environment isolation — Separate development, staging, and production semaphore state
- Pool differentiation — Prefix keys with a pool name to manage independent semaphore pools
How it works
The withSemaphorePrefix function returns a PluginFn that calls enhance on each adapter method that accepts a semaphore key. When an enhanced method is invoked, the plugin intercepts the call, prepends the configured prefix to the key argument, and forwards the modified arguments to the original method.
The plugin prefixes keys for the following methods:
| Method | Key argument | Pattern |
|---|---|---|
acquire | key within settings object | prefix + key |
forceReleaseAll | First argument (key) | prefix + key |
getState | First argument (key) | prefix + key |
refresh | First argument (key) | prefix + key |
release | First argument (key) | prefix + key |
Usage
import { withPlugin } from "eridu-tech/middleware";
import { MemorySemaphoreAdapter } from "eridu-tech/semaphore/memory-semaphore-adapter";
import { withSemaphorePrefix } from "eridu-tech/semaphore/plugins";
const adapter = new MemorySemaphoreAdapter();
// Apply the prefix plugin to the adapter
const prefixedAdapter = withPlugin(adapter, withSemaphorePrefix("pool-1:"));
Before/after behavior
Before — Semaphore keys are used as-is:
import { MemorySemaphoreAdapter } from "eridu-tech/semaphore/memory-semaphore-adapter";
const adapter = new MemorySemaphoreAdapter();
await adapter.acquire({
key: "connections",
slotId: "slot-1",
limit: 1,
ttl: null,
});
// -> acquires slot on "connections"
After — Semaphore keys are automatically prefixed:
import { withPlugin } from "eridu-tech/middleware";
import { MemorySemaphoreAdapter } from "eridu-tech/semaphore/memory-semaphore-adapter";
import { withSemaphorePrefix } from "eridu-tech/semaphore/plugins";
const adapter = new MemorySemaphoreAdapter();
// Apply the prefix plugin to the adapter
const prefixedAdapter = withPlugin(adapter, withSemaphorePrefix("pool-1:"));
await prefixedAdapter.acquire({
key: "connections",
slotId: "slot-1",
limit: 1,
ttl: null,
});
// -> acquires slot on "pool-1:connections"
Because withPlugin uses enhance under the hood, the same edge case applies: if one enhanced method internally calls another enhanced method via this, the middleware will apply twice. Be mindful of inter-method calls when applying plugins that enhance multiple methods on the same instance.
For more information about the withPlugin function and applying plugins to adapters, see the Middleware plugin documentation.