feat(async): add withPermit method to Semaphore#7180
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7180 +/- ##
==========================================
- Coverage 94.57% 94.56% -0.01%
==========================================
Files 636 637 +1
Lines 52142 52154 +12
Branches 9401 9401
==========================================
+ Hits 49315 49322 +7
- Misses 2249 2254 +5
Partials 578 578 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
1d7337c to
ee72f45
Compare
bartlomieju
left a comment
There was a problem hiding this comment.
Clean, correct, idiomatic addition. The implementation is solid — notably return await fn() correctly keeps the permit held until the task settles (without the await, the using disposal would release the permit before the work finished), and using guarantees release on throw. A couple of non-blocking suggestions inline.
| * automatically releasing the permit when the function completes. | ||
| * | ||
| * @example Usage | ||
| * ```ts no-assert |
There was a problem hiding this comment.
Consider dropping no-assert and asserting here, since withPermit returns a deterministic value. A self-verifying example is more useful than a console.log:
import { Semaphore } from "@std/async/unstable-semaphore";
import { assertEquals } from "@std/assert";
const sem = new Semaphore(1);
const result = await sem.withPermit(() => "result");
assertEquals(result, "result");(acquire/release use no-assert because they have nothing meaningful to assert; here you do.)
| await assertBlocks(sem.acquire(), () => sem.release()); | ||
| }); | ||
|
|
||
| Deno.test( |
There was a problem hiding this comment.
These tests use Semaphore(1) and a single call, so they cover the success and throw-and-release paths but not the actual point of withPermit — gating concurrency. Consider adding a test with new Semaphore(2) that launches several overlapping tasks and asserts the max in-flight never exceeds 2, and that a permit freed by a throwing task still lets a queued task proceed. The existing assertBlocks helper may help.
This is a common API pattern found in many concurrency libraries. It provides a highly convenient way to return the result of a protected task directly as an expression, entirely removing the boilerplate of manual semaphore management.
Usage Example: