Download the PHP package codysseydev/argus without Composer
On this page you can find all versions of the php package codysseydev/argus. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download codysseydev/argus
More information about codysseydev/argus
Files in codysseydev/argus
Package argus
Short Description Queue observability: records the lifecycle of queued jobs into a searchable store.
License MIT
Homepage https://github.com/codysseydev/argus
Informations about the package argus
Argus
Queue observability for Laravel. Argus records the lifecycle of every queued job (queued, processing, processed, failed, released) into a searchable store, behind a swappable storage interface, without slowing job processing, and exposes a query service to search jobs, replay a job's history, and group failures by root cause.
Argus ships no HTTP routes, controllers, auth, or UI. The consuming application owns its own RBAC/SSO/HTTP layer and calls the query service directly.
Requirements
- PHP
^8.5, Laravel^13.0 - PostgreSQL 16+ (default store), Redis (default buffer)
Install
Add the correlation whitelist and (optionally) a tenant resolver to config/argus.php.
Running the pipeline
Argus captures transitions in your existing queue workers automatically (via queue event listeners). Two processes complete the pipeline:
Argus schedules argus:partitions for you (daily at the configured time), so you
do not need to add it to routes/console.php. Adjust or disable it via config:
Querying recorded data
Inject Argus\Query\JobQueryService. It depends only on the backend-agnostic
read contract, so swapping the storage backend never touches your query code.
Build filters with Argus\Query\FilterBuilder; every criterion is optional and
all supplied criteria are ANDed together.
Return shapes are DTOs (JobSummary, TransitionRecord, FailureGroup), never
raw rows, and never contain customer payload data.
In-flight vs completed
A job with no terminal transition (no processed/failed) is in-flight:
JobSummary::isInFlight() returns true. Completed jobs return false and carry
a finishedAt. This distinguishes a still-running job from a finished one without
inspecting status.
Retention
retention_days (default 30) controls how much history is kept. argus:partitions
drops whole daily partitions older than the window. Changing the config value
changes what is dropped on the next run, with no code change.
Saved searches
A saved search persists a named JobFilter so an engineer can re-run it later. It
goes through the same swappable storage seam as everything else (Argus\Contracts\ SavedSearchStore, Postgres implementation selected by config('argus.store')).
Inject Argus\SavedSearches\SavedSearchService.
The filter is stored via a backend-agnostic codec (Argus\Query\FilterCodec), so a
reconstructed filter is equal to the original and re-runs to exactly the same rows.
Threshold alerts
Attach a rule to a saved search: when the search matches more than threshold jobs
over a rolling windowSeconds lookback, Argus fires an alert. Inject
Argus\Alerting\AlertService.
The evaluator (Argus\Alerting\AlertEvaluator) re-runs each enabled rule on a schedule.
It alerts on the transition into breach only: while a search keeps breaching it does
not re-alert every interval; it re-alerts after the search recovers (drops at or below
the threshold) and breaches again. cooldownSeconds additionally suppresses rapid
re-alerts caused by flapping.
Argus wires argus:evaluate-alerts onto Laravel's scheduler for you (every 5 minutes
by default), so you do not need to add it to routes/console.php:
Evaluation never blocks. Counting each rule is a cheap COUNT(*); delivery is dispatched
to a queued DeliverAlertJob (with retries and backoff). If a sink is down the job is
retried, so the alert is retained, not lost, and a slow or failing sink never stalls the
evaluator or other rules. (DeliverAlertJob is in capture.except, so Argus does not
observe its own alert deliveries.)
Adding a custom sink
Sinks live behind Argus\Contracts\AlertSink. Slack and a generic webhook ship in the box.
Adding PagerDuty, email, or anything else is implementing the interface and registering it,
no core changes:
Register it on the AlertSinkRegistry singleton from your own service provider, then
reference 'pagerduty' in any rule's sinks:
The buffer choice
The capture path must never block or slow a worker, so listeners do not write to
storage directly. Instead each listener does an O(1) LPUSH of one transition onto
a Redis list and returns immediately. A dedicated argus:ship daemon drains that
list in batches and writes to the store.
We deliberately did NOT ship transitions via a Laravel queued job: that would enqueue work onto the very queue system Argus observes (a feedback loop and added load). The Redis-list buffer keeps capture off the queue entirely.
Backpressure is built in: the shipper moves drained items to an inflight list and only
removes them after a successful store write (ack). If the store is slow or down, items
are never acked, so they stay buffered and are retried. Nothing is dropped and workers
are never stalled (they only ever push).
The buffer is an interface (Argus\Contracts\TransitionBuffer). Swapping the Redis list
for a Redis-stream outbox later is a single binding change; listeners and the shipper are
unaffected.
The storage-swap seam
Ingestion depends only on Argus\Contracts\TransitionStore (the write side). The concrete
store is resolved from config('argus.store'). Today postgres is implemented; a future
OpenSearch backend implements the same interface and is selected by changing one config
value, with zero changes to ingestion code. Backend-specific migrations live with their
backend (database/migrations/postgres) and are only loaded/published for that backend.
The read side (Argus\Contracts\TransitionQuery) is the same seam: the Postgres store
implements both the write and read contracts. The query layer (Argus\Query) compiles
to a backend-agnostic JobFilter and contains no SQL itself, so a future OpenSearch
backend implements the read methods and is selected by one config value.
Saved searches (Argus\Contracts\SavedSearchStore) and alert rules
(Argus\Contracts\AlertRuleStore) follow the identical pattern: an interface here, a
Postgres implementation under Storage/Postgres, selected by the same config('argus.store')
value. Their backend-specific migrations live in database/migrations/postgres with the
rest. Nothing in the service or alerting layer knows the backend.
What Argus never stores
Argus never writes raw job payloads. It captures only the correlation identifiers you
explicitly whitelist in config('argus.correlation.fields'). Anything not on that list is
never captured, so non-whitelisted data cannot be stored, searched, or returned.
Exception messages are the one free-text field Argus persists, so they are scrubbed at
ingestion before storage: emails, UUIDs, long hex tokens, and long digit runs are
replaced with [email] / [uuid] / [hex] / [id]. The stored value is already
redacted, so nothing sensitive is written or returned, including in the history and
failure-grouping views. Messages are also truncated and fingerprinted by root cause.
This is best-effort defense-in-depth on top of the hard guarantees above.
All versions of argus with dependencies
illuminate/console Version ^12.0|^13.0
illuminate/contracts Version ^12.0|^13.0
illuminate/database Version ^12.0|^13.0
illuminate/http Version ^12.0|^13.0
illuminate/queue Version ^12.0|^13.0
illuminate/redis Version ^12.0|^13.0
illuminate/support Version ^12.0|^13.0