Laravel
Connect a Laravel workload and verify its first real signal.
Laravel is one optional integration target. Keep the ingestion credential in environment-backed configuration, deliver telemetry outside the business path, and verify the resulting LatidoFlow run.
Install the official Laravel package
The optional latidoflow/laravel adapter supports PHP ^8.3 and Laravel 13. The doctor workflow below requires version 1.1.0 or later. Install it from Packagist or inspect the GitHub source. The language-neutral REST examples below remain a complete supported path if you do not use the package.
composer require latidoflow/laravel:^1.1
php artisan latidoflow:install
# .env
LATIDOFLOW_TOKEN=replace-with-secret-store-value
LATIDOFLOW_ENDPOINT=https://www.latidoflow.com
Issue the workspace token from Workspace integration and keep it in environment-backed configuration. Read it through the published config/latidoflow.php. Never call env() from application services, and never log the token, heartbeat URLs, or query values.
Configured
The package is installed and the token exists in environment-backed configuration.
Instrumented
Named schedules or allowlisted queue jobs can emit the intended signal.
Active
LatidoFlow accepted a real heartbeat or lifecycle event from that execution path.
Operational
The signal, alert route, and response workflow have all been verified.
php artisan latidoflow:sync and php artisan latidoflow:verify prove authentication and definition synchronization. They do not prove that a workload executed. A passing unit test or labeled setup simulation is not production evidence. Finish with a natural scheduler or worker run and read the resulting LatidoFlow run.
Diagnose setup, then prove execution
Give an existing foreground scheduled command a safe, stable name in routes/console.php. Replace the example command and frequency with your actual workload. Queue jobs require an exact job-class allowlist in the package configuration.
use Illuminate\Support\Facades\Schedule;
Schedule::command('reports:daily')
->daily()
->name('Daily reports');
php artisan config:clear
php artisan latidoflow:sync --dry-run
php artisan latidoflow:doctor --skip-sync
php artisan latidoflow:doctor
The doctor checks definitions, token format, cache, queue connections, and public monitoring-pipeline health. Blockers return a nonzero exit code. --skip-sync leaves remote definitions unchanged; the final command synchronizes them using the configured workspace token. Health checks do not send that token.
If your deployment caches configuration, rebuild it with php artisan config:cache and restart long-running workers and scheduler processes. Wait for the normal scheduled execution or run an authorized queue workload, then open Workspace integration and inspect its newly accepted run. Check the workload identity, timestamp, terminal result, and any configured business-output assertions. Doctor success is not proof that the workload ran or an alert was delivered.
For a blocker, check the indicated configuration category and rerun the doctor. Do not share tokens, raw responses, or customer data. Keep your previous Composer lockfile and customer configuration for rollback; follow the package's upgrade, rollback, and removal instructions. Restoring the adapter does not undo hosted definitions or monitoring history.
Choose the smallest complete integration
Completion heartbeat
Best for a scheduled command that only needs to report a real successful completion and optional output.
Runtime lifecycle
Best when queued, started, retry, progress, skipped, and terminal evidence must remain distinct.
Definition sync
Best when deployment tooling should keep projects, environments, and monitor definitions aligned.
Store configuration outside application code
# .env
LATIDOFLOW_BASE_URL=https://www.latidoflow.com
LATIDOFLOW_INGESTION_TOKEN=replace-with-secret-store-value
LATIDOFLOW_HEARTBEAT_URL=replace-with-secret-monitor-url
// config/services.php
'latidoflow' => [
'base_url' => env('LATIDOFLOW_BASE_URL', 'https://www.latidoflow.com'),
'ingestion_token' => env('LATIDOFLOW_INGESTION_TOKEN'),
'heartbeat_url' => env('LATIDOFLOW_HEARTBEAT_URL'),
],
Read environment values through configuration. Never call env() directly from application services, and never log these values.
Send a completion heartbeat out of band
After the business postcondition passes, enqueue a local telemetry job. The workload should not wait for LatidoFlow and should keep its original result if local telemetry enqueue is unavailable.
$result = $invoiceSync->run();
if ($result->recordsWritten() < 1) {
throw new RuntimeException('Invoice sync produced no records.');
}
try {
SendLatidoFlowHeartbeat::dispatch([
'output' => ['records_written' => $result->recordsWritten()],
])->onQueue('telemetry');
} catch (Throwable) {
// Keep the workload result; record only a constant safe diagnostic if required.
}
return $result;
use Illuminate\Support\Facades\Http;
public function handle(): void
{
Http::acceptJson()
->asJson()
->connectTimeout(1)
->timeout(3)
->post(config('services.latidoflow.heartbeat_url'), $this->payload)
->throw();
}
Configure bounded job retries and backoff on the telemetry queue. Do not copy raw exceptions, serialized jobs, request payloads, command arguments, or customer records into the heartbeat payload.
Use an ordered outbox for the full lifecycle
Queued, start, heartbeat, log, success, failure, and skipped events need stable correlation and ordering. Persist the telemetry intent locally with the logical job ID, let one dispatcher send events in order, and attach the returned run_uuid to later transitions.
- Generate the logical key before queue dispatch and reuse it across retries and redelivery.
- Do not report failure for a released or retryable Laravel job. Report terminal failure only when the queue lifecycle declares the job failed.
- Do not report success from a
finallyblock. Verify the business postcondition first. - Let missing-heartbeat and timeout evaluation represent worker loss; a killed worker cannot reliably send a final event.
Follow the language-neutral Runtime signals guide for exact routes, statuses, idempotency, and proof states.
Synchronize definitions from deployment tooling
Scheduled commands are first-class heartbeat definitions. Keep the portable monitor type as heartbeat and describe the workload source separately in metadata.
{
"project": {"name": "Billing", "slug": "billing"},
"environment": {
"name": "Production",
"slug": "production",
"kind": "production",
"is_production": true
},
"monitors": [
{
"name": "Invoice synchronization",
"slug": "invoice-sync",
"type": "heartbeat",
"check_interval_minutes": 15,
"grace_seconds": 120,
"timeout_seconds": 900,
"metadata": {"source_kind": "scheduled"},
"is_active": true
}
]
}
$response = Http::baseUrl(config('services.latidoflow.base_url'))
->withToken(config('services.latidoflow.ingestion_token'))
->acceptJson()
->asJson()
->connectTimeout(1)
->timeout(3)
->retry([100, 500], throw: false)
->post('/api/v1/monitors/sync', $definitions);
$response->throw();
$monitorUuid = $response->json('monitors.0.uuid');
Run definition sync in deployment or integration tooling, not on every business request. Validate the exact payload against the OpenAPI schema and save returned UUIDs without logging the token. Definition sync does not prove execution; verify a natural run from the intended scheduler or worker.
Test the boundary
- Use
Http::fake()to assert method, path, authorization header, timeout behavior, and secret-free payloads. - Use queue fakes to prove the business path enqueues telemetry only after the success condition and preserves retry control flow.
- Test remote failure separately and prove it does not change the business return value or exception.
- Finish with a real worker or scheduler execution and read the resulting LatidoFlow run. A passing unit test proves instrumentation, not active production evidence.