PHPackages                             kwhorne/askr-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. kwhorne/askr-laravel

ActiveLibrary[Caching](/categories/caching)

kwhorne/askr-laravel
====================

Laravel integration for the Askr application server: session, cache, locks, queue and broadcasting drivers plus automatic page caching (pages are tagged with the models they read) — Redis-free, with an optional durable/replicated SQL Anywhere backend.

v1.4.13(3w ago)086↓66.7%MITPHPPHP ^8.3

Since Jul 17Pushed 2w agoCompare

[ Source](https://github.com/kwhorne/askr-laravel)[ Packagist](https://packagist.org/packages/kwhorne/askr-laravel)[ Docs](https://github.com/kwhorne/askr)[ RSS](/packages/kwhorne-askr-laravel/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (9)Versions (16)Used By (0)

askr-laravel
============

[](#askr-laravel)

Laravel integration for the [Askr](https://github.com/kwhorne/askr) application server. It wires Askr's **in-binary, shared-memory** services into Laravel's driver system, so a single-box app needs **no Redis**:

DriverWhat it replaces`SESSION_DRIVER=askr`Redis / DB / `file` sessions`CACHE_STORE=askr`Redis cache, counters, rate limiting, `Cache::lock()``QUEUE_CONNECTION=askr`Redis / DB queues`BROADCAST_CONNECTION=askr`Redis pub/sub + a WebSocket server (Laravel Echo)### Durable, replicated (multi-box)

[](#durable-replicated-multi-box)

The drivers above are unchanged whether the server uses the L1 shared-memory tier (single box, ephemeral) or the durable, replicated **L2 SQL Anywhere**tier. Run the server built with `--features sql-backend` and set `ASKR_QUEUE_DB` / `ASKR_CACHE_DB` / `ASKR_BROADCAST_DB` to a database path (an embedded file, an embedded replica, or a `sqld`-managed database) to get durable jobs, a shared/edge cache, and cross-node broadcasting — no app changes.

`Driver [askr] not supported`
-----------------------------

[](#driver-askr-not-supported)

`SESSION_DRIVER=askr` (or `CACHE_STORE`/`QUEUE_CONNECTION`) without this package installed. The drivers come from here, not from the server:

```
composer require kwhorne/askr-laravel
php artisan package:discover      # only needed if you installed with --no-scripts
```

In worker mode the failure is a 500 on every route that touches the driver, and Askr's log names it: `uncaught InvalidArgumentException escaped the request handler: Driver [askr] not supported.`

Why the session driver matters
------------------------------

[](#why-the-session-driver-matters)

Running Laravel in a long-lived worker (Octane-style, which is how Askr serves) exposes a real trap: **`SESSION_DRIVER=array` leaks** — the array handler keeps every session in the PHP heap until it hits `memory_limit`. The alternatives each give something up. Askr's shared-memory driver gives up nothing:

`SESSION_DRIVER`Fast?No heap leak?No lock?No extra server?`array`✅❌ (OOMs)✅✅`file`❌✅✅✅`database` (SQLite)❌✅❌✅`redis`✅✅✅❌**`askr`**✅✅✅✅Measured: **~11–15k req/s with flat 8 MB per worker** (sessions live in shared memory, not the heap), persisting across every worker process.

Install
-------

[](#install)

```
composer require kwhorne/askr-laravel
```

The service provider is auto-discovered — no manual registration.

Configure
---------

[](#configure)

```
SESSION_DRIVER=askr
CACHE_STORE=askr
QUEUE_CONNECTION=askr
```

Add the cache/queue store definitions (or rely on the defaults):

```
// config/cache.php → 'stores'
'askr' => ['driver' => 'askr'],

// config/queue.php → 'connections'
'askr' => ['driver' => 'askr', 'queue' => 'default', 'retry_after' => 90],
```

Run
---

[](#run)

Start Askr with the matching shared-memory regions enabled:

```
askr serve \
  --root public --worker-script vendor/askr/worker.php \
  --workers auto \
  --cache-slots 16384 --cache-large-slots 4096 \
  --queue-slots 8192
```

- `--cache-slots` — the small region (≤ 4 KB values: counters, locks, cache).
- `--cache-large-slots` — the large region (up to 64 KB: sessions, fragments).
- `--queue-slots` — the job queue.

Run queue workers in the same binary:

```
askr serve … --queue 4 --queue-script vendor/laravel/framework/… # or artisan queue:work
```

Notes
-----

[](#notes)

- These drivers call Askr's `askr_cache_*` / `askr_queue_*` builtins, which exist only when the app is served by Askr with the regions enabled. Under a plain `php artisan` invocation the session driver degrades to a no-op; don't point a non-Askr process at these drivers for real work.
- The shared-memory regions are sized at startup and evict oldest-first when full — size `--cache-large-slots` for your peak concurrent session count.

MIT © Knut W. Horne

Automatic page caching (`askr.cache`)
-------------------------------------

[](#automatic-page-caching-askrcache)

> **The server needs a response cache for this to do anything.** Start Askr with `--response-cache 512` (or `[cache] response_slots = 512`). Without it the middleware still sets its header, the server has nowhere to put the page, and nothing is cached — which looks like the middleware not working. `X-Askr-Cache` on the response tells you which it is: `MISS`/`HIT` means the cache is on, no header at all means it isn't.

Page caching is rare in Laravel not because it's slow to set up, but because keeping the tags right is a job nobody wants: one forgotten dependency serves stale content, so teams switch it off. Askr can watch instead.

```
Route::get('/products/{product}', ProductController::class)
    ->middleware('askr.cache:300');              // fresh 300s

Route::get('/', HomeController::class)
    ->middleware('askr.cache:300,60,86400');     // ttl, swr, stale-if-error
```

There is no tag list. The middleware records every Eloquent model the response read (via the `retrieved` event) and tags the cached page with them, so `$product->save()`clears exactly the pages that showed that product — across every worker, immediately.

**Precision while it's cheap, safety when it isn't.** A cached entry holds up to 8 tags, so:

The response readIt's taggedA change clearsa few modelsper instance (`products:42`)only the pages showing that productmany modelsper class (`products`)every page that listed productsmore classes than fitnothing — and it isn't cached—The last row matters: Askr **refuses** to cache a response carrying more tags than an entry holds, rather than storing one whose invalidation silently doesn't work. A page you can't invalidate is worse than a page you didn't cache.

Creating a model clears the class tag too — a brand-new product has no page of its own to invalidate, but the listing that should now include it does.

### When it declines to cache

[](#when-it-declines-to-cache)

The middleware only marks a response cacheable when it can tell the page is shared:

- the request is a `GET`/`HEAD` returning 200;
- nobody is authenticated (`$request->user() === null`);
- the response sets no cookie, and the session holds nothing beyond its own bookkeeping (a flash message, a cart, a session-bound form all count as "personal").

The server adds its own guards underneath: only anonymous requests are cacheable at all, and `Set-Cookie` is stripped on store.

### Find out what's worth caching first

[](#find-out-whats-worth-caching-first)

```
askr serve --traffic-log /tmp/traffic.jsonl   # run for an hour
askr cache-report /tmp/traffic.jsonl
```

That reports the hit rate each route would reach, the PHP time it would save, and — the part that matters — whether the page was **byte-identical for every visitor**during the sample. Add `askr.cache` to the routes it calls safe.

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance95

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

15

Last Release

27d ago

Major Versions

v0.9.3 → v1.4.02026-08-04

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3391304?v=4)[gets](/maintainers/gets)[@gets](https://github.com/gets)

---

Top Contributors

[![kwhorne](https://avatars.githubusercontent.com/u/11035264?v=4)](https://github.com/kwhorne "kwhorne (11 commits)")

---

Tags

laravelcachequeuesessionBroadcastingshared memorypage cacheaskr

### Embed Badge

![Health badge](/badges/kwhorne-askr-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/kwhorne-askr-laravel/health.svg)](https://phpackages.com/packages/kwhorne-askr-laravel)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3365.5M359](/packages/psalm-plugin-laravel)[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k59.5M719](/packages/laravel-scout)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k17.6M170](/packages/laravel-pulse)[fleetbase/core-api

Core Framework and Resources for Fleetbase API

1346.4k29](/packages/fleetbase-core-api)[illuminate/auth

The Illuminate Auth package.

10528.8M1.4k](/packages/illuminate-auth)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k161.4k2](/packages/mike-bronner-laravel-model-caching)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
