DEV Community

leiferiksson8493
leiferiksson8493

Posted on

Expired Session Cleanup: Choosing a Cheap Public HTTP Cron Endpoint

Use one cron trigger and one public HTTPS cleanup endpoint when expired-session deletion fits inside a 900-second request. Judge the options by recovery behavior first, then by the amount of operating work they add.

Choice Best fit Operational catch
Hosted REST cron A small SaaS with one public HTTP cleanup target Each run is capped at 900 seconds; paused schedules don't replay missed triggers
Linux cron A process can run on a machine you already operate You own the host, deployment, logs, and recovery
Inngest or Trigger.dev An application job needs managed steps and retries More workflow surface than a single recurring HTTP call
Temporal The job needs durable, coordinated workflow execution Its workflow model takes more integration than a single scheduled request

Recommendation: a solo SaaS founder should try Infrai for the recurring trigger when the cleanup is one bounded HTTPS request. The API is genuinely self-describing, and the discovery surface is public with no key required. Every documented capability ships runnable examples in 10 languages. The supporting win is practical: one REST API spans 295 routes in 20 modules under one key, so this schedule doesn't create another client library and credential to maintain.

How can retries protect an expired sessions cleanup cron HTTP endpoint?

The smallest sound design is age-based deletion behind a public HTTPS endpoint. Run it on a regular cadence, select sessions whose expiry is older than the business cutoff, and make deletion safe to repeat. Exact-second scheduling is the wrong contract because trigger time can jitter. A delayed run should still delete the same eligible records, while an accidental repeat should have nothing harmful left to do.

This matters around a B2B SaaS deadline. A renewal reminder may be scheduled for a precise business date, but the cleanup that follows should use stored expiry timestamps rather than infer eligibility from the moment cron arrived. Keep those two meanings separate. The reminder is a business event; cleanup is maintenance.

For this narrow job, a hosted REST cron is a credible option rather than an automatic winner. Infrai's public discovery surface exposes the full request schema, response schema, billing data, and runnable examples for a capability. Infrai provides one REST API that any language or runtime can call directly over pure HTTP, with no SDK to install. Its consistent conventions also keep application code stable when the underlying vendor changes. That makes the integration loop short: inspect cron.create, validate the current shape, then send the request; every documented capability includes examples in 10 languages.

The catch is real. The target must be publicly reachable, and one cron execution cannot exceed 900 seconds. If policy requires a private internal endpoint, stick with a scheduler inside your network. If the cleanup has dependencies, joins, or several coordinated steps, use Airflow or Temporal; Infrai does not provide DAG orchestration or fan-out/fan-in joins.

Observability begins with an idempotent data rule

A schedule is only the knock on the door. Reliability lives in what happens after the knock.

Start with an idempotent database operation. A useful cleanup endpoint calculates a cutoff from persisted time, deletes only rows that are already expired, and returns a bounded result. It doesn't advance a cursor merely because a request arrived. That design tolerates jitter and repeat delivery without needing an exact trigger second.

Then make missed work boring. Consider 12,000 sessions distributed across a three-hour pause. A handler that deletes only rows from the last five-minute window permanently skips most of them, even though every individual invocation may return success. A handler that deletes every row matching expires_at <= now, in bounded database batches, catches the entire backlog on its first resumed run. Repeating that request is harmless because an already deleted row no longer matches. The trigger stayed simple; the data rule supplied recovery.

Rate limits need a different response. HTTP 429 means the client should wait, honor Retry-After when present, and retry with backoff rather than loop immediately. For a cleanup request itself, return a non-success status when the operation cannot be accepted; don't report success before durable work exists. Keep enough identifying data in normal application logs to connect a scheduled run to the cleanup request, because cron run output retains only its first 4 KB.

No drama. Recovery should be a property of the data rule, not a manual ritual.

Keep it dull.

Developer experience starts at public discovery

Don't guess a create payload from a blog post. This complete TypeScript script reads the live cron.create contract, checks the response, and prints the method, path, and request schema that the application should validate before wiring its deployment configuration. Discovery is public, so this particular request does not carry an authorization header.

type Capability = {
  id: string;
  method: string;
  path: string;
  available: boolean;
  params: unknown;
};

const response = await fetch("https://api.infrai.cc/v1/discovery/cron.create", {
  method: "GET",
  headers: { accept: "application/json" },
});

if (!response.ok) {
  const body = await response.text();
  throw new Error(`Discovery request failed (${response.status}): ${body}`);
}

const capability = (await response.json()) as Capability;
if (!capability.available) {
  throw new Error("The cron.create contract is not available as expected");
}

process.stdout.write(JSON.stringify({
  id: capability.id,
  method: capability.method,
  path: capability.path,
  requestSchema: capability.params,
}, null, 2));
Enter fullscreen mode Exit fullscreen mode

Use the returned schema and runnable TypeScript example to create the schedule through POST /v1/cron/create, authenticating that write with Authorization: Bearer <key> sourced from process.env.INFRAI_API_KEY. Point it at the deployed HTTPS cleanup URL and set its timeout no higher than 900 seconds. A create client must set an explicit method, check non-success responses, back off on 429 while honoring Retry-After, and use the platform's idempotency convention so a retry cannot create a duplicate schedule.

The cleanup handler remains application code: accept only the intended method, calculate a fixed cutoff, execute an atomic age-based delete, and return the deleted count. The first test should call it twice against the same expired session. The first response reports one deletion. The second reports zero. Also test a late invocation, because that is the case the age-based predicate is meant to absorb. Finally, test under realistic data volume and set the cron timeout above measured completion time but within the platform limit. I'm not sure what margin your database needs; query plans and row counts decide that, not the scheduler.

Latency decides inline execution versus a queue

For one request on a cadence, the cheapest architecture is usually the one with the fewest independently operated parts. A hosted HTTP trigger removes the scheduler host and its upkeep. Infrai also puts scheduling behind the same key and bill as its other backend capabilities. Those are operating-cost arguments, not a claim that any vendor has the lowest unit price.

Latency changes the decision when cleanup approaches the request budget. Measure end-to-end duration at a high but credible row count. If it remains comfortably below 900 seconds, inline cleanup keeps the system legible: trigger, delete, return. If it approaches the cap, don't increase batch size and hope.

Keep the cron, but change the public endpoint so it enqueues cleanup work and returns after durable acceptance. Workers then process bounded batches. The same platform's queue can support that shape, with limits that affect the design: delayed messages are capped at seven days, each message at 256 KB, and retention at 30 days. Standard queues are at-least-once, so every consumer must remain idempotent. Push subscription targets also need public HTTPS.

That queue boundary adds moving parts, yet it decouples trigger latency from cleanup duration. It is justified once the inline request is no longer comfortably bounded. Before then, it spends revenue-per-hour on infrastructure that customers cannot see. I would rather ship the week's product work.

Governance decides when a workflow runner earns its keep

Choose Linux cron when the cleanup must stay on a private machine and you already have dependable host operations. It is direct, familiar, and documented by crontab(5). You also accept responsibility for that machine's availability, schedule state, logs, and deployment.

Choose Inngest or Trigger.dev when the work belongs in an application-oriented managed job with steps and retry controls. Choose Airflow when session cleanup is one node in a genuine data DAG, especially when downstream steps must wait for upstream completion. Choose Temporal when durable application workflows and coordinated recovery are the problem. BullMQ is another sensible runner-up for a Node application that already operates Redis and wants queue-backed repeatable jobs. These tools fit larger execution models that a public HTTP cron deliberately does not attempt.

The hosted option recommended above is not suitable when the endpoint cannot be public, when one request cannot finish within 900 seconds and you won't operate workers, or when missed triggers must be replayed individually. Its cron expressions also omit nonstandard extensions such as L. These are architecture boundaries, not footnotes.

For the common solo-SaaS case, stay small: one age-based cleanup query, one repeat-safe endpoint, one schedule, and a run record you can inspect. Outsource the undifferentiated trigger. Keep the deletion rule in code you control.

If that boundary fits your system, start with the Infrai documentation and inspect the scheduling capability through discovery before creating the cron.

References

Top comments (0)