{"id":18401383,"url":"https://github.com/dozyio/js-counting-semaphore","last_synced_at":"2025-07-09T20:04:32.707Z","repository":{"id":259802310,"uuid":"879455705","full_name":"dozyio/js-counting-semaphore","owner":"dozyio","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-28T00:55:56.000Z","size":192,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-12T17:55:57.157Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dozyio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-27T23:53:58.000Z","updated_at":"2024-10-28T00:55:49.000Z","dependencies_parsed_at":"2024-10-28T04:13:17.004Z","dependency_job_id":"8e87cb32-d181-468b-9c11-870ed67c2c54","html_url":"https://github.com/dozyio/js-counting-semaphore","commit_stats":null,"previous_names":["dozyio/js-counting-semaphore"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/dozyio/js-counting-semaphore","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-counting-semaphore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-counting-semaphore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-counting-semaphore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-counting-semaphore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dozyio","download_url":"https://codeload.github.com/dozyio/js-counting-semaphore/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-counting-semaphore/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264502620,"owners_count":23618657,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T02:38:40.995Z","updated_at":"2025-07-09T20:04:32.687Z","avatar_url":"https://github.com/dozyio.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JS/TS Counting Semaphore\n\n**Counting-Semaphore** is a lightweight, robust, and TypeScript-compatible library that provides a counting semaphore implementation for managing concurrent access to shared resources in asynchronous environments. It is ideal for scenarios where you need to limit the number of simultaneous operations, such as controlling access to a pool of database connections, managing parallel API requests, or synchronizing tasks in Node.js applications.\n\n## Table of Contents\n\n- [Features](#features)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basic Example](#basic-example)\n- [API Reference](#api-reference)\n  - [Constructor](#constructor)\n  - [Methods](#methods)\n    - [`acquire(): Promise\u003cvoid\u003e`](#acquirepromisevoid)\n    - [`release(): Promise\u003cvoid\u003e`](#releasepromisevoid)\n  - [Properties](#properties)\n    - [`permits: number`](#permits-number)\n    - [`maxPermits: number`](#maxpermits-number)\n- [Debugging](#debugging)\n- [Error Handling](#error-handling)\n- [License](#license)\n\n## Features\n\n- **Concurrency Control:** Limit the number of concurrent operations accessing a shared resource.\n- **Asynchronous Support:** Designed for use with asynchronous functions (`async/await`).\n- **Thread-Safe:** Ensures atomic operations to prevent race conditions.\n- **Debugging Support:** Optional debug mode for detailed logging.\n- **TypeScript Support:** Fully typed for seamless integration with TypeScript projects.\n- **Lightweight:** Minimal dependencies and overhead.\n\n## Installation\n\nYou can install `counting-semaphore` via npm:\n\n```bash\nnpm install counting-semaphore\n```\n\nOr using Yarn:\n\n```bash\nyarn add counting-semaphore\n```\n\n## Usage\n\n### Basic Example\n\nHere's a simple example demonstrating how to use the `Counting-Semaphore` to control access to a shared resource.\n\n```typescript\n// src/example.ts\n\nimport { Semaphore } from 'counting-semaphore';\n\n// Initialize a semaphore with 2 permits\nconst semaphore = new Semaphore(2, { debug: true, name: 'ResourceSemaphore' });\n\n// Function to simulate an asynchronous task\nconst asyncTask = async (id: number) =\u003e {\n  try {\n    console.log(`Task ${id}: Requesting to acquire a permit.`);\n    await semaphore.acquire();\n    console.log(`Task ${id}: Permit acquired. Performing task...`);\n\n    // Simulate task duration\n    await new Promise((resolve) =\u003e setTimeout(resolve, 2000));\n\n    console.log(`Task ${id}: Task completed. Releasing permit.`);\n    await semaphore.release();\n  } catch (error) {\n    console.error(`Task ${id}: Failed to acquire permit - ${(error as Error).message}`);\n  }\n};\n\n// Start multiple asynchronous tasks\n(async () =\u003e {\n  asyncTask(1);\n  asyncTask(2);\n  asyncTask(3);\n  asyncTask(4);\n})();\n```\n\n### Expected Output\n\nWhen you run the example, you should see output similar to the following, illustrating how the semaphore manages permits and queues tasks when no permits are available:\n\n```\nSemaphore initialized with maxPermits: 2 for \"ResourceSemaphore\"\nTask 1: Requesting to acquire a permit.\nResourceSemaphore Semaphore: Attempting to acquire a permit. Current permits: 2\nResourceSemaphore Semaphore: Permit acquired. Remaining permits: 1\nTask 1: Permit acquired. Performing task...\nTask 2: Requesting to acquire a permit.\nResourceSemaphore Semaphore: Attempting to acquire a permit. Current permits: 1\nResourceSemaphore Semaphore: Permit acquired. Remaining permits: 0\nTask 2: Permit acquired. Performing task...\nTask 3: Requesting to acquire a permit.\nResourceSemaphore Semaphore: Attempting to acquire a permit. Current permits: 0\nResourceSemaphore Semaphore: No permits available. Queuing the request.\nTask 4: Requesting to acquire a permit.\nResourceSemaphore Semaphore: Attempting to acquire a permit. Current permits: 0\nResourceSemaphore Semaphore: No permits available. Queuing the request.\nTask 1: Task completed. Releasing permit.\nResourceSemaphore Semaphore: Releasing a permit.\nResourceSemaphore Semaphore: Resolving a queued acquire request.\nResourceSemaphore Semaphore: Permit acquired from queue.\nTask 3: Permit acquired. Performing task...\nTask 2: Task completed. Releasing permit.\nResourceSemaphore Semaphore: Releasing a permit.\nResourceSemaphore Semaphore: Resolving a queued acquire request.\nResourceSemaphore Semaphore: Permit acquired from queue.\nTask 4: Permit acquired. Performing task...\nTask 3: Task completed. Releasing permit.\nResourceSemaphore Semaphore: Releasing a permit.\nResourceSemaphore Semaphore: Permit released. Available permits: 1\nTask 4: Task completed. Releasing permit.\nResourceSemaphore Semaphore: Releasing a permit.\nResourceSemaphore Semaphore: Permit released. Available permits: 2\n```\n\n## API Reference\n\n### Constructor\n\n```typescript\nnew Semaphore(permits: number, opts?: SemaphoreOpts)\n```\n\n- **Parameters:**\n  - `permits` (`number`): The maximum number of concurrent permits. Must be a non-negative integer.\n  - `opts` (`SemaphoreOpts`, optional):\n    - `debug` (`boolean`): If `true`, enables debug logging. Defaults to `false`.\n    - `name` (`string`): An optional name for the semaphore, used in debug logs. Defaults to an empty string.\n\n- **Example:**\n\n  ```typescript\n  const semaphore = new Semaphore(3, { debug: true, name: 'MySemaphore' });\n  ```\n\n### Methods\n\n#### `acquire(): Promise\u003cvoid\u003e`\n\nAcquires a permit from the semaphore. If a permit is available, it is granted immediately. Otherwise, the request waits until a permit is released.\n\n- **Returns:** `Promise\u003cvoid\u003e` that resolves when the permit is acquired.\n\n- **Throws:** No direct throws, but if the semaphore is improperly used, it may indirectly throw errors from internal methods.\n\n- **Example:**\n\n  ```typescript\n  await semaphore.acquire();\n  // Critical section: perform operations that require a permit\n  await semaphore.release();\n  ```\n\n#### `release(): Promise\u003cvoid\u003e`\n\nReleases a permit back to the semaphore. If there are pending `acquire` requests, the next one is granted a permit.\n\n- **Returns:** `Promise\u003cvoid\u003e` that resolves when the permit is released.\n\n- **Throws:**\n  - `Error` if attempting to release more permits than the semaphore was initialized with.\n\n- **Example:**\n\n  ```typescript\n  await semaphore.release();\n  ```\n\n### Properties\n\n#### `permits: number`\n\nGets the current number of available permits.\n\n- **Type:** `number`\n\n- **Example:**\n\n  ```typescript\n  console.log(semaphore.permits); // Outputs the current number of available permits\n  ```\n\n#### `maxPermits: number`\n\nGets the maximum number of permits the semaphore was initialized with.\n\n- **Type:** `number`\n\n- **Example:**\n\n  ```typescript\n  console.log(semaphore.maxPermits); // Outputs the maximum number of permits\n  ```\n\n## Debugging\n\nThe `Counting-Semaphore` supports an optional debug mode, which provides detailed logging of semaphore operations. To enable debugging, set the `debug` option to `true` when initializing the semaphore.\n\n```typescript\nconst semaphore = new Semaphore(2, { debug: true, name: 'DebugSemaphore' });\n```\n\n**Sample Debug Output:**\n\n```\nSemaphore initialized with maxPermits: 2 for \"DebugSemaphore\"\nDebugSemaphore Semaphore: Attempting to acquire a permit. Current permits: 2\nDebugSemaphore Semaphore: Permit acquired. Remaining permits: 1\nDebugSemaphore Semaphore: Releasing a permit.\nDebugSemaphore Semaphore: Resolving a queued acquire request.\nDebugSemaphore Semaphore: Permit acquired from queue.\n```\n\n## Error Handling\n\n**Best Practices:**\n\n- Always ensure that each `acquire` call is paired with a corresponding `release` to prevent deadlocks.\n- Use try-catch blocks around critical sections to handle potential errors gracefully.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdozyio%2Fjs-counting-semaphore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdozyio%2Fjs-counting-semaphore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdozyio%2Fjs-counting-semaphore/lists"}