Async-Redis

 view release on metacpan or  search on metacpan

examples/async-job-queue/SPEC.md  view on Meta::CPAN

Workers should simulate job processing with `Future::IO->sleep($delay)` rather
than CPU work. The point is event-loop concurrency, not parallel CPU execution.

The app should coordinate all tasks with futures, for example:

- producer future enqueues all jobs
- worker futures loop until they receive a stop sentinel
- heartbeat future loops until the processed count reaches the target
- main future waits for producer, workers, and heartbeat to finish

## Queue Semantics

Startup:

- delete `async-job-queue:jobs`
- delete `async-job-queue:processed`
- delete `async-job-queue:in-flight`
- push jobs `job-1` through `job-N`

Worker loop:

- `BLPOP async-job-queue:jobs 0`
- if the value is a stop sentinel, exit
- add the job to `async-job-queue:in-flight`
- print that the worker started the job
- `await Future::IO->sleep($delay)`
- remove the job from `async-job-queue:in-flight`
- increment `async-job-queue:processed`
- print that the worker finished the job

Shutdown:

- after all real jobs are processed, push one stop sentinel per worker
- workers consume sentinels and exit
- final summary prints elapsed time, processed count, and expected sequential
  time

The stop sentinel should be a value that cannot collide with generated job
names, for example `__async_job_queue_stop__`.

## Output Requirements

Output must be human-readable and timestamped relative to process start.

It should make queueing and async behavior obvious. Example shape:

```text
[ 0.00s] queued 10 jobs
[ 0.01s] worker-1 started job-1
[ 0.01s] worker-2 started job-2
[ 0.25s] heartbeat queue=8 in_flight=2 processed=0
[ 1.51s] worker-1 finished job-1
[ 1.51s] worker-1 started job-3
[ 1.51s] worker-2 finished job-2
[ 1.51s] worker-2 started job-4
[ 1.75s] heartbeat queue=6 in_flight=2 processed=2
[ 7.55s] done processed=10 workers=2 elapsed=7.55s sequential_about=15.00s
```

The README should explain that the heartbeat lines are the key proof: the
process continues running other async work while workers are blocked in Redis
or waiting on simulated work.

## CLI

Keep the first version simple, but allow the demo to be tweaked:

```text
examples/async-job-queue/app.pl [options]

Options:
  --jobs N       number of jobs to enqueue, default 10
  --workers N    number of workers, default 2
  --delay SEC    simulated seconds per job, default 1.5
  --help         show usage
```

Validation:

- `--jobs` must be a positive integer
- `--workers` must be a positive integer
- `--delay` must be a positive number

## Dependencies

Use only modules already required by the distribution or Perl core where
possible:

- `Async::Redis`
- `Future`
- `Future::AsyncAwait`
- `Future::IO`
- `Getopt::Long`
- `Time::HiRes`
- `FindBin`

Do not require PAGI, AnyEvent, IO::Async-specific setup, or a web server.

## Documentation Requirements

`examples/async-job-queue/README.md` should include:

- what the example demonstrates
- how to start Redis with the existing `examples/docker-compose.yml`
- how to run the app from the project root
- sample output
- why separate worker connections are used
- what to look for in the output

`examples/README.md` should add an `async-job-queue` section with a short
description and one run command.

## Test And Verification Plan

Manual smoke test:

```bash
perlbrew use perl-5.40.0@default
docker compose -f examples/docker-compose.yml up -d
REDIS_HOST=localhost perl examples/async-job-queue/app.pl --jobs 6 --workers 2 --delay 0.2
```



( run in 0.562 second using v1.01-cache-2.11-cpan-df04353d9ac )