Deployment
AI assistant
Build this with Claude Code, Cursor or Copilot
Copy a Tessero-tuned prompt for Deployment, grounded in 16 real API signatures , into your IDE's AI. No chatbot, just exact context.
1. Check the machine
vendor/bin/tessero doctor # FFI package php --ri tessero # extension php artisan tessero:doctor # Laravel: both, plus the selected backend
doctor exits non-zero when something needs attention, so it can gate a
deployment pipeline. Run it with the same php.ini as production (for FPM:
php -c /etc/php/8.4/fpm/php.ini vendor/bin/tessero doctor). The CLI
often has a different configuration.
2. Pick the backend per runtime
| Runtime | Recommended | Configuration |
|---|---|---|
CLI scripts, cron, artisan commands |
either | FFI: ffi.enable=1, or preload (the CLI SAPI may still call FFI::cdef) |
Queue workers (queue:work, Horizon) |
extension, or FFI | same as CLI; set threads for dedicated heavy queues |
| PHP-FPM / Apache mod_php | extension | FFI needs ffi.enable=preload + the preload script (below) |
| Octane (Swoole, RoadRunner, FrankenPHP) | extension | FFI: preload as for FPM, or ffi.enable=1 if you accept that risk (see [Security(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/security.md)) |
3. PHP-FPM and Apache
With the extension (simplest)
; /etc/php/8.4/mods-available/tessero.ini extension = tessero tessero.memory_budget = 256M tessero.threads = 1
Enable it for the FPM SAPI and restart FPM. Nothing else is needed.
With the FFI package
Keep PHP's secure default ffi.enable=preload and preload the library:
ffi.enable = preload opcache.enable = 1 opcache.preload = /var/www/app/vendor/tessero/tessero/resources/preload.php opcache.preload_user = www-data
vendor/bin/tessero php-ini prints these lines with your real paths.
What the preload script does:
- Writes a small header with
#define FFI_SCOPE "tessero"and#define FFI_LIB "<absolute path>"to the temp directory and callsFFI::load()on it. - Does the same for the first LP64 OpenBLAS with LAPACKE it finds (scope
tessero_blas).TESSERO_BLASoverrides the search. - Preloads every class under
src/. This is required. Withffi.enable=preload, PHP lets only preloaded code call FFI APIs such asFFI::newandFFI::cast.
Preloaded code is fixed when FPM starts. Restart (not reload) FPM after
every composer install/update that changes Tessero, or requests will run
the old code against the new library.
Verify on a staging host with the same check CI runs:
bash vendor/tessero/tessero/tests/e2e/preload.sh
It starts php -S with ffi.enable=preload and FFI::cdef forbidden, and
runs arithmetic and LAPACK through the preloaded scopes.
4. Octane
- Prefer the extension. Octane workers are long-lived, and the extension has no preload step to keep in sync with deployments.
tessero/laravelre-applies threads and the memory budget at the start of every request and task. Without Laravel, callEngine::setMaxThreads()/Engine::setMemoryBudget()(or the FFI equivalents) at the start of each request.- Watch for arrays kept in static properties or singletons. They stay for the worker's lifetime ([Memory and threads(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/memory-and-threads.md)).
- Set
--max-requestsas usual. Tessero does not leak, but it bounds the damage of application code that does.
5. Queue workers and batch jobs
Heavy numerical work (large MILPs, MDPs with millions of states, simulations) belongs on a dedicated queue with its own worker pool:
php artisan queue:work --queue=numerics --memory=1024 --timeout=900
--memorywatches PHP memory only. Native memory is capped byTESSERO_MEMORY_BUDGET([Memory and threads(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/memory-and-threads.md)).- On a dedicated pool, set
TESSERO_THREADSto the cores each worker may use: for example 4 workers × 2 threads on an 8-core host. --timeoutmust exceed the longest solve. Solver calls run in C and cannot be interrupted part-way by PHP'smax_execution_time(see [Troubleshooting(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/troubleshooting.md#a-solve-runs-longer-than-max_execution_time)). Bound them withmaxIter/nodeLimitinstead.
6. Deployment checklist
-
doctorpasses under the production php.ini of every SAPI you use. - A memory budget is set per worker (
tessero.memory_budgetorTESSERO_MEMORY_BUDGET). -
threadsis 1 under FPM unless you have sized for more. - Public endpoints validate array input with a size cap (
NumericArray(maxElements: …)). - FFI + FPM: preload configured, and FPM restarts on deploy.
- Health check includes
tessero:doctor --jsonortessero info --json([Monitoring(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/monitoring.md)). - The same backend and version is used in staging and production.