{"id":51046395,"url":"https://github.com/netlogix/netlogix.jobqueue.polling","last_synced_at":"2026-06-24T16:00:29.884Z","repository":{"id":365798823,"uuid":"1273510567","full_name":"netlogix/Netlogix.JobQueue.Polling","owner":"netlogix","description":"A periodic baseline poll plus a coalesced immediate re-poll on job completion, gated by a capacity check so racing polls never exceed the allowed parallelism.","archived":false,"fork":false,"pushed_at":"2026-06-18T15:38:51.000Z","size":7,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-19T00:59:34.538Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/netlogix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-18T15:38:09.000Z","updated_at":"2026-06-18T15:40:53.000Z","dependencies_parsed_at":"2026-06-19T00:59:36.373Z","dependency_job_id":null,"html_url":"https://github.com/netlogix/Netlogix.JobQueue.Polling","commit_stats":null,"previous_names":["netlogix/netlogix.jobqueue.polling"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/netlogix/Netlogix.JobQueue.Polling","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlogix%2FNetlogix.JobQueue.Polling","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlogix%2FNetlogix.JobQueue.Polling/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlogix%2FNetlogix.JobQueue.Polling/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlogix%2FNetlogix.JobQueue.Polling/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/netlogix","download_url":"https://codeload.github.com/netlogix/Netlogix.JobQueue.Polling/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlogix%2FNetlogix.JobQueue.Polling/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34651752,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2026-06-22T14:01:04.166Z","updated_at":"2026-06-22T14:01:05.094Z","avatar_url":"https://github.com/netlogix.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Netlogix.JobQueue.Polling\n\nThis package provides a small, dependency-free poll scheduler for ReactPHP based\njob workers.\n\nThere are two main goals:\n\n1. Poll for new work on a baseline interval without burning CPU when idle.\n2. Pick up freed capacity immediately after a job finishes, without waiting for the\n   next interval — while never starting more work in parallel than allowed.\n\nIt is the shared polling core used by both `Netlogix.JobQueue.FastRabbit` (one job at\na time per worker) and `Netlogix.JobQueue.Scheduled` (N jobs in parallel).\n\n\n## Installation\n```bash\ncomposer require netlogix/jobqueue-polling\n```\n\n\n## The problem it solves\n\nA naive worker either polls aggressively (high CPU even when there is nothing to do) or\nonly on a slow interval (low throughput, because a freed slot waits up to one interval\nbefore the next job is picked up).\n\n`PollScheduler` combines a periodic baseline poll with an on-demand \"immediate\" poll\nthat callers trigger when a job completes. Immediate polls are coalesced to a single\npending future tick, and every poll is gated by a capacity check, so a burst of\ncompletions racing the periodic timer can never start more work than capacity allows.\n\nThe correctness invariant: the capacity check and the slot occupation done inside\n`$tryToPickUpWork` run synchronously within a single, uninterrupted loop frame\n(ReactPHP is single threaded, no `await` in between). Therefore any number of stacked\nor racing polls collapse to \"fill up to capacity, then bail\".\n\n\n## Usage\n\n`PollScheduler` is DI-free — instantiate it with `new` or the static `create()`\nfactory, also from a standalone worker binary that has no Flow object management.\n\n```php\nuse Netlogix\\JobQueue\\Polling\\PollScheduler;\n\n$scheduler = PollScheduler::create(\n    loop: $loop,                              // React\\EventLoop\\LoopInterface\n    tryToPickUpWork: fn () =\u003e $this-\u003epickUp($pool),   // picks up as much work as capacity allows\n    hasCapacity: fn () =\u003e count($pool) \u003c $parallel,   // cheap, side-effect free\n    interval: 0.1,                            // baseline poll interval in seconds\n);\n\n$scheduler-\u003estart();                          // register the periodic baseline poll\n\n// ... when a job finishes (e.g. in the process EXIT/SUCCESS/ERROR handler):\n$scheduler-\u003erequestImmediatePoll();           // pick up the next job without waiting for the interval\n\n// ... during a drain/shutdown phase:\n$scheduler-\u003estop();                           // cancel the baseline poll (does not stop the loop)\n```\n\n`$tryToPickUpWork` is responsible for respecting capacity itself. The two canonical\nshapes:\n\n- **Single concurrency** (FastRabbit): `hasCapacity: fn () =\u003e count($pool) === 0`, and\n  `tryToPickUpWork` reserves exactly one job when free.\n- **N concurrency** (Scheduled): `hasCapacity: fn () =\u003e count($pool) \u003c $parallel`, and\n  `tryToPickUpWork` drains in a `while (count($pool) \u003c $parallel)` loop.\n\nThe scheduler's own capacity pre-check is an early-out; the callback's internal limit is\nthe authoritative bound.\n\n\n## API\n\n- `PollScheduler::create(LoopInterface $loop, Closure $tryToPickUpWork, Closure $hasCapacity, float $interval): static`\n  / equivalent constructor.\n- `start(): self` — register the periodic baseline poll.\n- `requestImmediatePoll(): void` — request an out-of-band poll as soon as possible;\n  coalesced to at most one pending future tick.\n- `stop(): void` — cancel the baseline poll and stop picking up further work (drain\n  phase); does not stop the event loop.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetlogix%2Fnetlogix.jobqueue.polling","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetlogix%2Fnetlogix.jobqueue.polling","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetlogix%2Fnetlogix.jobqueue.polling/lists"}