Skip to content

release/v0.7.71 - #725

Merged
roncodes merged 3 commits into
mainfrom
release/v0.7.71
Oct 19, 2026
Merged

roncodes merged 3 commits into
mainfrom
release/v0.7.71

Conversation

@roncodes

@roncodes roncodes commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Release v0.7.71. Merging into main tags v0.7.71 through the release workflow.

FrankenPHP / Octane startup fix

Octane 2.22.0 requires FrankenPHP 1.13.0 and checks the binary each time octane:frankenphp starts. On the 1.12.4 base image it answers its own "download the latest binary?" prompt with yes (no TTY), moves /usr/local/bin/frankenphp aside, downloads a generic build to base_path('frankenphp'), deletes the original, and then runs the path it emptied: exec: /usr/local/bin/frankenphp: not found, exit 127, on every start. The image builds fine; only startup fails.

main still locks Octane 2.19.1, so the published v0.7.70 images are not affected. The next composer update would have pulled 2.22.0 under the old ^2.3 range.

  • Base image dunglas/frankenphp:1.13.1-php8.2-bookworm.
  • Build-time guard. docker/scripts/assert-frankenphp-version.php runs after composer install. It reads $requiredFrankenPhpVersion from the installed Octane (by reflection, not grep) and compares it with frankenphp version. If the image's binary is older, or either version can't be read, the build fails and names both versions. This covers every target built from docker/Dockerfile: ci.yml bake, install-smoke.yml, the published images and the cloud CD build.
  • Octane range ^2.3 → ~2.22.0, locked at 2.22.0 (composer update laravel/octane only). A new Octane minor version now needs a deliberate bump alongside the base image, and the guard enforces that pairing.

install-smoke.yml already boots the app-release image and checks :8000/health on this PR, so it shows that 1.13.1 actually serves.

Components

The composer lock moves only fleetbase/core-api and fleetbase/fleetops-api. The pnpm lock moves only @fleetbase/fleetops-engine. The submodule pointers are at the peeled tag commits. No engine routes changed, so router.map.js is untouched.

Verified in CI

The build-guard step ran in the image build and printed FrankenPHP 1.13.1 meets laravel/octane's minimum (1.13.0). The fresh-install smoke test booted the app-release image on 1.13.1 and served :8000/health.

… needs a newer FrankenPHP

Octane 2.22.0 requires FrankenPHP 1.13.0 and checks the binary each time
octane:frankenphp starts. On the 1.12.4 base image it answered its own
download prompt with yes, moved /usr/local/bin/frankenphp aside, downloaded
a generic build to base_path('frankenphp'), deleted the original and then
ran the emptied path: "exec: /usr/local/bin/frankenphp: not found", exit
127 on every start. The v0.7.70 cloud deploy crash-looped on this while the
image itself built fine.

- Base image: dunglas/frankenphp:1.13.1-php8.2-bookworm.
- docker/scripts/assert-frankenphp-version.php runs after composer install
  and fails the build when the image's FrankenPHP is older than the
  installed Octane's $requiredFrankenPhpVersion, naming both versions.
- laravel/octane is held to ~2.22.0 (locked 2.22.0), so a new Octane minor
  version comes in only with a deliberate bump alongside the base image.
@codecov

codecov Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (ffb34b0) to head (deae3b5).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##                main      #725   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
  Complexity        38        38           
===========================================
  Files            196       196           
  Lines           4092      4092           
===========================================
  Hits            4092      4092           
Flag Coverage Δ
api 100.00% <ø> (ø)
console 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Fleetbase API performance — release/v0.7.71

p95: 1.99 s · p99: 2.36 s · Throughput: 17.4 req/s · Errors: 0% · Thresholds: ✅ PASS · Rate-limit isolation: ✅ PASS

Release release/v0.7.71
Commit 85b42552a6f7
Ref refs/pull/725/merge
Started 2026-10-19T06:47:59.827Z
Duration 314s
Per-key limit 120 req/min
Run workflow run

Performance

Scope Requests req/s avg p50 p90 p95 p99 max Errors p95 vs v0.7.70 p99 vs v0.7.70
All requests 3,649 17.38 654 ms 460 ms 1.78 s 1.99 s 2.36 s 3.41 s 0% 🔺 +88% 🔺 +86%
Reads 2,527 12.03 752 ms 481 ms 1.90 s 2.08 s 2.52 s 3.41 s 0% 🔺 +87% 🔺 +91%
Writes 1,122 5.34 433 ms 428 ms 783 ms 940 ms 1.24 s 1.77 s 0% 🔺 +84% 🔺 +82%

Endpoints (slowest p95 first)

Endpoint Requests req/s p50 p90 p95 p99 max Errors p95 vs v0.7.70 Budget
GET /v1/orders filtered 229 1.09 1.76 s 2.21 s 2.52 s 3.03 s 3.34 s 0% 🔺 +101% ⚠️ over
GET /v1/orders 522 2.49 1.78 s 2.18 s 2.32 s 2.85 s 3.41 s 0% 🔺 +82% ⚠️ over
GET /v1/places 248 1.18 557 ms 940 ms 1.10 s 1.36 s 1.46 s 0% 🔺 +79% ⚠️ over
POST /v1/orders 390 1.86 516 ms 854 ms 992 ms 1.25 s 1.77 s 0% 🔺 +83% ✓
POST /v1/contacts 109 0.52 526 ms 932 ms 989 ms 1.17 s 1.29 s 0% 🔺 +70% ✓
GET /v1/contacts 153 0.73 430 ms 805 ms 969 ms 1.18 s 1.41 s 0% 🔺 +96% ⚠️ over
GET /v1/service-areas 32 0.15 248 ms 673 ms 949 ms 1.32 s 1.45 s 0% 🔺 +120% ⚠️ over
PUT /v1/orders/:id 333 1.59 406 ms 782 ms 926 ms 1.15 s 1.47 s 0% 🔺 +93% ✓
GET /v1/orders/:id 425 2.02 359 ms 689 ms 889 ms 1.24 s 1.77 s 0% 🔺 +87% ⚠️ over
GET /v1/service-rates 54 0.26 257 ms 672 ms 866 ms 1.17 s 1.25 s 0% 🔺 +132% ⚠️ over
GET /v1/vehicles 143 0.68 333 ms 657 ms 800 ms 990 ms 1.37 s 0% 🔺 +114% ⚠️ over
GET /v1/contacts/:id 121 0.58 325 ms 745 ms 796 ms 1.02 s 1.23 s 0% 🔺 +72% ✓
GET /v1/fleets 82 0.39 247 ms 612 ms 777 ms 1.04 s 1.09 s 0% 🔺 +61% ✓
GET /v1/issues 44 0.21 289 ms 735 ms 770 ms 1.15 s 1.20 s 0% 🔺 +118% ✓
GET /v1/places/:id 186 0.89 304 ms 665 ms 768 ms 1.02 s 1.06 s 0% 🔺 +82% ✓
GET /v1/vendors 104 0.50 298 ms 614 ms 765 ms 1.08 s 1.17 s 0% 🔺 +87% ✓
POST /v1/places 156 0.74 323 ms 612 ms 752 ms 1.38 s 1.52 s 0% 🔺 +84% ✓
PUT /v1/places/:id 64 0.30 337 ms 558 ms 743 ms 918 ms 1.02 s 0% 🔺 +84% ✓
GET /v1/drivers 148 0.70 302 ms 599 ms 727 ms 990 ms 1.46 s 0% 🔺 +86% ✓
PUT /v1/contacts/:id 70 0.33 350 ms 683 ms 716 ms 972 ms 1.22 s 0% 🔺 +62% ✓
GET /v1/fuel-reports 36 0.17 242 ms 619 ms 692 ms 891 ms 955 ms 0% 🔺 +38% ✓

Budgets (p95): reads < 800 ms, writes < 1500 ms — report only. Changes are against v0.7.70; 🔺/🟢 mark a change of 20% or more.

Not measured: GET /v1/drivers/:id (no drivers to read), GET /v1/vehicles/:id (no vehicles to read)

Regression gate vs v0.7.70 — ❌ REGRESSED

Scope p95 Baseline p95 Change Result
Reads 2.08 s 1.11 s 🔺 +87% (+965 ms) ❌ regressed
Writes 940 ms 511 ms 🔺 +84% (+429 ms) ❌ regressed

A scope regresses when it is more than 35% and more than 150 ms slower p95 than the previous release. On a release PR a regression is re-measured once before it fails the check.

Rate-limit isolation traffic

Noisy tenant (NOISY key, normal limit)

Endpoint Requests req/s p50 p95 p99 max Errors 429s
POST /v1/orders 189 2.10 87.8 ms 112 ms 130 ms 156 ms 0% 65
PUT /v1/orders/:id 172 1.91 55.8 ms 69.0 ms 91.4 ms 107 ms 0% 56

Noisy errors exclude the expected 429 responses (the 429s column); latencies include them.

Victim tenant (VICTIM key, different org)

Endpoint Requests req/s p50 p95 p99 max Errors
GET /v1/orders 15 0.20 213 ms 272 ms 319 ms 330 ms 0%
GET /v1/orders/:id 15 0.20 47.8 ms 52.7 ms 58.1 ms 59.5 ms 0%
POST /v1/orders 15 0.20 105 ms 129 ms 161 ms 169 ms 0%
PUT /v1/orders/:id 15 0.20 71.3 ms 77.6 ms 79.4 ms 79.9 ms 0%
GET /v1/places 15 0.20 62.4 ms 65.1 ms 67.4 ms 68.0 ms 0%

Anonymous console route

Endpoint Requests req/s p50 p95 p99 max Errors
GET /int/v1/settings/branding 38 0.51 10.3 ms 13.8 ms 14.4 ms 14.6 ms 0%

Isolation result — ✅ PASS

One tenant floods the API far above its per-key limit while a second tenant and an anonymous console visitor keep working. Only the flooding tenant may be throttled.

Check Observed Result
Noisy tenant is throttled 121 of 361 requests got 429 (33.5%) ✅ PASS
Every 429 carries Retry-After 0 missing ✅ PASS
Every 429 carries X-RateLimit-* 0 missing ✅ PASS
Victim tenant never throttled 0 × 429 in 75 requests ✅ PASS
Anonymous console route never throttled 0 × 429 in 38 requests ✅ PASS

Thresholds — ✅ PASS

Metric Threshold Observed Result
http_req_failed rate<0.01 0% ✅ PASS
victim_throttled count==0 0 ✅ PASS
public_probe_throttled count==0 0 ✅ PASS
noisy_throttled count>0 121 ✅ PASS
noisy_429_missing_retry_after count==0 0 ✅ PASS
victim_requests count>0 75 ✅ PASS
public_probe_requests count>0 38 ✅ PASS

Run

Base URL http://localhost:8000
Throughput ramping to 16 concurrent virtual users over 210s (request rate is what the API sustains)
Endpoints weighted catalogue across orders, places, contacts, drivers, vehicles, fleets, vendors, service areas/rates, issues and fuel reports
Latency budget (p95) reads < 800 ms, writes < 1500 ms
Noisy flood 4 req/s for 90s (create/update)
Victim 1 req/s for 75s, starting 15s into the flood
Public probe GET /int/v1/settings/branding every 2s, anonymous
Max error rate 1.00% (expected 429s on the noisy tenant excluded)
Total requests 4,171 (failed 0%)
Checks 4,079 passed, 0 failed

Confirmation run: latency regression confirmed.

Workflow run · full HTML report in the k6-report artifact

@roncodes
roncodes marked this pull request as ready for review October 19, 2026 07:05
@roncodes
roncodes merged commit 89ff7c3 into main Oct 19, 2026
11 of 12 checks passed
@roncodes
roncodes deleted the release/v0.7.71 branch October 19, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] /api/int/v1/geocoder/query returns [] for valid addresses while places/search resolves them

1 participant