Dev Log: 2026-06-22 - Configurable Schedulers, Load-Test Toolkits, and an MCP Server
DEV Community

Dev Log: 2026-06-22 - Configurable Schedulers, Load-Test Toolkits, and an MCP Server

Thread 1 - Make scheduled tasks configurable instead of code-only

If you've run a Laravel app for any length of time, you know the scheduler lives in code: routes/console.php or the kernel, a wall of ->daily(), ->everyFiveMinutes(), ->cron(...). That's fine until the day an operator - not a developer - needs to change when something runs. Then you're shipping a deploy just to nudge a cron expression. Silly.

Today's work pulled scheduler configuration into a settings-backed UI. The pattern is worth stealing: instead of the schedule being a literal in code, the code reads its cadence from a settings store, and there's an admin screen to edit it.

// Instead of a hardcoded cadence...
$schedule->command('subscriptions:reconcile')->daily();

// ...read it from settings, with a sane default baked in.
$schedule->command('subscriptions:reconcile')
    ->cron($this->schedulerSettings->reconcileCron ?? '0 2 * * *');

Two things made this clean. First, a SchedulerSettings object (Spatie's settings pattern) so the values are typed, cached, and migratable - not loose rows you Setting::get('...') by string key. Second, grouping the more user-facing schedules behind their own modal rather than dumping every cron in one giant form. A subscription-related schedule belongs next to subscriptions; a platform schedule belongs in admin. Same data, but organized by who needs to touch it.

The edge case to watch: a UI-editable cron is a foot-gun if you let people type nonsense. Validate the expression on save, and always keep a default so a blank setting can never silently disable a job.

Thread 2 - A load-testing toolkit is documentation you can run

The second thread was building out a load-testing toolkit with capacity-planning notes for predictable peak periods - the kind of seasonal spikes where traffic is 10x normal for a known window.

Here's the mindset shift I want to pass on: a load test isn't a one-off you run in a panic before a big day. It's a committed artifact - scripted scenarios, a runner, a comparison step, all in the repo. The value isn't just the numbers; it's that "what does the system do at peak?" becomes a command anyone can run, not tribal knowledge in one engineer's head.

The structure that worked:

  • Separate scenario configs for each traffic profile (normal hours vs. a couple of distinct peak shapes)
  • A shared library of common setup
  • A single runner that takes a scenario
  • A compare script so you can put two runs side by side

Capacity planning then lives as a markdown doc next to the scripts - assumptions written down, so next quarter you're updating a document instead of re-deriving everything.

The teachable bit: when you script peak scenarios explicitly, you're forced to name your assumptions - expected concurrent users, request mix, acceptable p95. That act of naming is half the value. A vague "it should handle the spike" becomes "here's the profile, here's the run, here's where it bent."

Thread 3 - An MCP server, done with auth taken seriously

The biggest thread was wiring a Model Context Protocol (MCP) server into a Laravel app so AI agents can call typed, permission-checked tools instead of poking at the UI. I gave this its own full write-up because the auth story deserves the space - dual authentication (Sanctum for first-party callers, OAuth 2.1 for delegated third-party agents), every tool mapped to an RBAC ability, and outputs trimmed to deliberate projections so a tool can't leak a whole model.

The one-line version: an MCP server is a reception desk for AI agents - check who they are, check what they're allowed to do, perform exactly one named task, hand back a structured answer. Everything else stays behind the desk. (Full breakdown in the focused post.)

The thread that ties them together

Configurable schedulers, committed load tests, a tool-based AI surface - on the face of it, unrelated. But they're the same instinct three times: take something that was implicit (a cadence buried in code, peak behavior that lived in someone's memory, "the AI can sort of use our API") and make it explicit and operable - configured, scripted, authorized. That's most of what "making a system mature" actually means.

What's next: validating those UI-editable cron expressions hard, and tightening the OAuth consent step on the MCP path.

Comments

No comments yet. Start the discussion.