惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
Stack Overflow Blog
Stack Overflow Blog
L
LINUX DO - 最新话题
Google Online Security Blog
Google Online Security Blog
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
www.infosecurity-magazine.com
www.infosecurity-magazine.com
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
V
Vulnerabilities – Threatpost
K
Kaspersky official blog
S
Schneier on Security
B
Blog
The Register - Security
The Register - Security
SecWiki News
SecWiki News
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Security Affairs
T
The Blog of Author Tim Ferriss
G
Google Developers Blog
T
Tenable Blog
P
Proofpoint News Feed
Apple Machine Learning Research
Apple Machine Learning Research
D
DataBreaches.Net
S
Secure Thoughts
Security Latest
Security Latest
H
Heimdal Security Blog
The Hacker News
The Hacker News
O
OpenAI News
AWS News Blog
AWS News Blog
量子位
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
腾讯CDC
U
Unit 42
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
T
The Exploit Database - CXSecurity.com
NISL@THU
NISL@THU
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Hugging Face - Blog
Hugging Face - Blog
The Last Watchdog
The Last Watchdog
Recorded Future
Recorded Future
V2EX - 技术
V2EX - 技术
爱范儿
爱范儿
F
Full Disclosure

Railway Blog

Where Railway is, and where it's going (Summer 2026) PaaS vs IaaS vs SaaS: What Each Means and Who Should Pick What in 2026 The Best Continuous Deployment Tools in 2026 The Best PaaS for Multi-Region Deployments in 2026 The Best Platforms for Monorepo Deployments in 2026 Compliance Isn't a Feature, It's a Posture What is BYOC (Bring Your Own Cloud)? A Developer's Guide for 2026 The Best Managed Kubernetes Hosting in 2026 The Best Container Registries in 2026 The Vanilla Cloud Tax: What Rolling Your Own on AWS Actually Costs What is a PaaS? A Developer's Guide for 2026 The Best Cloud Observability and Logging Tools in 2026 The Best PostgreSQL Hosting for Developers in 2026 The Best Multi-Region Hosting Platforms in 2026 The Best Platforms to Deploy AI Apps in 2026 (Not the Models, the Apps Around Them) The Agent-Native Cloud: What It Means and Why It Matters Incident Report: May 19, 2026- GCP Account Suspension Counting to 3 with a new builder processing 50M+ monthly builds Railway iOS preview now available via TestFlight Kill your onboarding: selling to 10,000+ new users a day Your AI wants to nuke your database. Guardrails fix that. Better Rails for Agents: A New Remote MCP and Railway Agent in the CLI Moving Railway's Frontend Off Next.js One command deploys, there's a Stripe APP for that From registrar to deployed: buying a domain inside Railway A letter to open source builders who deserve more Networking is a black box, we used eBPF to open it Heroku Walked So Railway Can Run Security Features Your Security Team Will Love Railway Runs Open Source, Now We're Funding It Railway raises $100M Series B to unburden the builders Deploy autoscaling services, AI Workflow automation, and LLM APIs Without Kubernetes Hosting Postgres with GeoLite2: a practical guide to IP geolocation, data loading, and updates Serverless functions vs containers: CI/CD, database connections, cron jobs, and long-running tasks Hosting Postgres with pgvector: provider tradeoffs, migrations, indexes, and tuning Introducing the Railway integration on Delve.co Secure Cloud Hosting for Compliance: A Practical Guide for Startups and Regulated Industries How G2X Unlocked Rapid Experimentation at Scale with Railway MindFort Runs 100+ AI Pen Testing Agents Without Their Previous $10k AWS Bill How Bilt's Marketing Engineering Team Delivers at Scale with Railway Railway Technology Partners: Earn Revenue on Templates You Didn't Build ~$1 Million Paid to Developers Who Built Railway Templates CI/CD for Modern Deployment: From Manual Deploys to PR Environments Kernel Powers 1,000+ AI Agents on $444/Month of Railway Infrastructure Deploy Full-Stack TypeScript Apps: Architectures, Execution Models, and Deployment Choices Railway vs Cloudflare: How Their Architectures Differ and When to Use Each Monitoring & Observability: Using Logs, Metrics, Traces, and Alerts to Understand System Failures Logs, Metrics, and Traces: What Does Each Signal Tell You? Server rendering benchmarks: Railway vs Cloudflare vs Vercel Top five Heroku alternatives Comparing top PaaS and deployment providers Pricing to Encourage Use The F in SOC2 stands for functional Deploy Together, Earn Together: Introducing Railway Partnerships How We Oops-Proofed Infrastructure Deletion on Railway Bring Back the Free Plan Railway MCP - Stateful, Serverful, Pay-per-use Infrastructure Hackathon: Winners Announced! Mark Your Calendar: Railway User Hackathon with Prizes Launching Railway's Affiliate Program Zero-Touch Bare Metal at Scale Ssh, We’re Announcing One More Thing! $1M for Open Source Introducing Central Station Speed Isn’t Just About Code, It’s About Where That Code Runs One-Second Deploys? We Didn’t Believe It Either Why We’re Moving on From Nix Railway V3: Faster and Cheaper How to Migrate from Cloudflare Pages to Railway Supercharging Directus on Railway with a Static Frontend How to Migrate from AWS Lambda to Railway Deploy Triton Inference Server on Railway How to Handle Database Connection Pooling Building a NestJS App on Railway Manually Optimize Deployments on Railway Implement a GitHub Actions Testing Suite Scaling a SaaS application on Railway Building a SaaS application on Railway Deploy a Dart App on Railway, Part 2 Deploy a Dart App on Railway, Part 1 Implementing Feature Flags from Scratch Cron Jobs with Django and GitHub Actions Deploy Offen on Railway Queues on Railway Working with NX, Railway and CI/CD Automated PostgreSQL Backups Using GitLab CI/CD with Railway Migrating From Heroku To Railway Cron Jobs on Railway Deploy Beam on Railway Deploy Authorizer on Railway Deploying Monorepo Applications How to Backup and Restore Your Postgres Database How to Backup Your Redis Instance Deploy Cusdis on Railway Deploy Ghost on Railway Using Github Actions with Railway Deploy Calendso (cal.com) on Railway Self-hosted website analytics Use Notion as a CMS for your NextJS blog
Run Scheduled and Recurring Tasks with Cron
Mahmoud Abdelwahab · 2025-11-26 · via Railway Blog

Avatar of Mahmoud Abdelwahab

Mahmoud Abdelwahab

This guide explains how to deploy scheduled and recurring tasks with cron. It introduces the execution model that governs cron jobs, examines common use cases, and outlines the operational practices that keep these tasks reliable in production. It also describes how to deploy cron-based workloads on Railway.

What are cron and cron jobs?

Cron provides a time-based execution system that runs commands according to predefined schedules. A cron job is a schedule-command pair. The schedule defines when a task should start, and the command specifies what the system executes at that moment.

Cron evaluates schedules at fixed time boundaries, checks them against the current time, and runs any command whose schedule matches. Each run is independent. Cron does not store job history, track partial progress, or coordinate concurrency across entries. It launches a process with the configured environment and leaves error handling to the invoked program.

This model suits tasks that run at predictable intervals without external orchestration. Workloads that need coordination across nodes, queue semantics, or recovery guarantees fall outside cron’s scope.

Cron Job Use Cases

Cron’s constraints shape the categories of work it handles reliably. Cron aligns with workloads that run on predictable intervals and do not require coordination across multiple workers. These tasks complete in a single invocation, tolerate being triggered strictly by time, and can handle their own error conditions. Here are some use cases:

  • Data backups, log rotation, and cleanup: Periodic maintenance fits well into cron’s model. Backups, archival routines, temporary file cleanup, and log rotation all rely on fixed schedules and run as isolated operations. They benefit from cron’s simplicity and do not need queueing or distributed orchestration.
  • Batch processing: Many batch workloads operate on daily or hourly intervals. Examples include report generation, data extraction pipelines with fixed windows, and transformations that process a known set of inputs. As long as a batch task can complete within its scheduled window and does not depend on event-driven triggers, cron provides a stable trigger mechanism.
  • Scheduled notifications and email delivery: Cron can initiate periodic notifications such as system summaries, daily digests, or alert checks. The underlying logic must handle its own rate limits and delivery failures, because cron itself provides no retry semantics.
  • Syncing or fetching external data: Recurring synchronization tasks, such as pulling data from external APIs or refreshing caches, fit the model when they can be executed independently and tolerate occasional delays or transient failures.
  • Automation for DevOps and CI tasks: Infrastructure-oriented routines such as certificate checks, dependency audits, container cleanup, or automated environment validation often run on fixed intervals. These tasks are usually short-lived and isolated, which makes cron an appropriate trigger mechanism.

Understanding Cron Schedules

Cron schedules use a compact notation to express when a task should start. The format encodes minutes, hours, days, months, and weekdays in a fixed sequence of fields. Cron evaluates these fields independently and starts a task when all specified conditions match the current time. Understanding this model is essential for predicting how a job behaves under real workloads.

The five-field format

A cron schedule contains five space-separated fields:

* * * * *
│ │ │ │ └── weekday (0–6)
│ │ │ └──── month (1–12)
│ │ └────── day of month (1–31)
│ └──────── hour (0–23)
└────────── minute (0–59)

Each field represents an exact match or a set of matches. Cron checks all fields at the start of each minute. A schedule triggers only when every field matches the current timestamp. Cron performs no cross-field reasoning. For example, a job that specifies both a day of month and a weekday will fire whenever either field matches, which can create schedules that run more often than intended.

Wildcards, ranges, lists, and steps

Cron supports a compact expression language in each field.

  • Wildcards. An asterisk matches every possible value in the field. For example, * * * * * runs every minute.
  • Ranges. A range such as 1-5 matches all values between the endpoints.
  • Lists. Comma-separated values create a set. For example, 1,15 in the day-of-month field runs on the 1st and 15th.
  • Steps. A slash introduces a step. */5 in the minute field triggers every 5 minutes. Steps also apply to ranges, such as 1-10/2, which matches 1, 3, 5, 7, and 9.

These operators combine freely within a field. Cron does not attempt to simplify or interpret intent. It treats the final set of values as the rule.

Examples of common schedules

Several patterns appear frequently in production systems:

  • 0 * * * * runs at the start of every hour
  • 0 0 * * * runs once per day at midnight
  • /10 * * * * runs every 10 minutes
  • 0 3 * * 1 runs every Monday at 03:00
  • 30 2 1 * * runs on the first day of each month at 02:30
  • 30 * * * * runs every hour at the 30th minute
  • 15 15 * * * runs every day at 3:15 PM
  • 0 8 * * 1 runs every Monday at 8:00 AM
  • 0 0 1 * * runs every month on the 1st day at 12:00 AM
  • 30 14 * 1 0 runs every Sunday at 2:30 PM in January
  • 30 9 * * 1-5 runs every weekday (Monday to Friday) at 9:30 AM
  • 0 6 2 * * runs every 2nd day of the month at 6:00 AM

The simplicity of these expressions is useful, but misalignment between human expectations and cron’s matching rules is common. Testing schedules before deployment avoids unintended triggers.

Timezone considerations

Cron interprets schedules according to the host’s timezone unless configured otherwise. Systems running in containers or distributed environments often default to UTC. Tasks that depend on local time boundaries, such as end-of-day processing or region-specific reporting, must account for this.

Running cron in UTC keeps behavior predictable across deployments and avoids drift caused by daylight saving transitions. If local time behavior is required, the environment should set consistent timezone configuration and ensure the task logic tolerates DST adjustments.

What are best practices for Cron Jobs?

Cron does not manage state, coordination, or error recovery. Production reliability depends on how each job behaves when triggered and how it interacts with external systems.

Writing idempotent tasks

A cron job should safely tolerate repeated execution with the same inputs. Idempotence prevents corrupted state when a job retries logic internally or when operators need to re-run a task manually. Database upserts are a common pattern:

INSERT INTO reports (id, generated_at, data)
VALUES ($1, NOW(), $2)
ON CONFLICT (id) DO UPDATE
SET generated_at = NOW(), data = EXCLUDED.data;

Idempotence also applies to file generation, API requests, and cache refresh logic. Deterministic filenames, unique request keys, and guard checks help prevent partial updates.

Logging and monitoring

Cron provides no built-in history. Every job must log its start, success, and error conditions explicitly. A simple TypeScript structure keeps logs predictable:

async function main() {
  const startedAt = new Date().toISOString();
  console.log("job_start", { ts: startedAt });

  try {
    await runJob();
    console.log("job_success", { ts: new Date().toISOString() });
  } catch (err) {
    console.error("job_error", { ts: new Date().toISOString(), err });
    process.exitCode = 1;
  }
}

These logs become the foundation for observability and alerting.

Keeping tasks short and efficient

Cron assumes the task completes before the next scheduled trigger. Jobs that approach their interval duration risk overlapping with themselves, creating contention or double processing. Reducing batch size, dividing work into smaller windows, or offloading heavier computation to a dedicated worker system avoids these issues.

Cleaning up connections and resources

Cron will not clean up leaked resources. Network clients, database pools, file handles, and buffers must be released explicitly:

import { Client } from "pg";

async function runJob() {
  const client = new Client({ connectionString: process.env.DATABASE_URL });

  try {
    await client.connect();
    await processWork(client);
  } finally {
    await client.end(); // avoid leaked connections across runs
  }
}

Even small leaks accumulate across many invocations.

Avoiding overlaps and race conditions

Cron does not serialize job execution. If a previous run is still active, cron will start another. A database-level advisory lock provides a simple and robust guard:

-- Try to acquire a lock identified by an integer key.
-- Returns true only if this process acquires the lock.
SELECT pg_try_advisory_lock(42) AS acquired;

A job should check this before doing work:

const res = await client.query(
  "SELECT pg_try_advisory_lock($1) AS acquired",
  [42]
);

if (!res.rows[0].acquired) {
  console.log("job_skip", { reason: "lock_not_acquired" });
  return;
}

Only the instance that acquires the lock proceeds. Others exit immediately, avoiding conflicting updates.

Testing schedules before deployment

Cron expressions are compact and easy to misinterpret. Values that combine day-of-month and weekday fields are especially error-prone. Before deploying a schedule, preview it using a tool such as crontab.guru.

This makes timing assumptions visible and prevents unexpected triggering patterns.

When cron is enough versus when to use a scheduler or queue

Cron is suitable when jobs are short, independent, and tolerant of fixed time triggers. It is less suitable for workloads that require task chaining, backpressure, retries with guarantees, distributed coordination, or progress tracking. Systems such as job schedulers and message queues provide durability, visibility, and structured workflows that cron does not model.

These practices make cron predictable under load and resilient to the failure modes inherent in timer-driven execution.

Cron Jobs on Railway

Railway’s cron system provides scheduled execution without keeping a service running between tasks. This eliminates the need for an in-process scheduler such as node-cron or Quartz, and avoids paying for idle compute. The platform starts a service only when work needs to be performed, runs the task, and then returns the service to an inactive state.

CleanShot 2025-11-23 at 21.33.20@2x.png

Execution model

Railway evaluates cron expressions in UTC and triggers a job by running the service’s start command at the scheduled time. The process is expected to execute a single task, close all external resources, and exit. Open database connections, active HTTP clients, background timers, or any other long-lived handles keep the process alive after the task is complete.

Since Railway does not automatically terminate active deployments, a job that stays running blocks the next scheduled execution. If the previous run is still active at the next trigger time, the new run is skipped. Most skipped executions trace back to code paths that never return, unclosed connections, pending promises, or background work that was not awaited.

RAILWAY CRON EXECUTION FLOW

    ┌─────────────────────────────────────────────────────────────────┐
    │                     CRON SCHEDULER (UTC)                        │
    └───────────────────────────┬─────────────────────────────────────┘
                                │
                                ▼
                    ┌───────────────────────┐
                    │   Trigger Scheduled   │
                    │     Start Command     │
                    └───────────┬───────────┘
                                │
                                ▼
    ╔═══════════════════════════════════════════════════════════════════╗
    ║                        JOB EXECUTION                              ║
    ╠═══════════════════════════════════════════════════════════════════╣
    ║                                                                   ║
    ║   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐          ║
    ║   │   Execute    │──▶│    Close     │──▶│     Exit     │          ║
    ║   │    Task      │   │  Resources   │   │   Process    │          ║
    ║   └──────────────┘   └──────────────┘   └───────┬──────┘          ║
    ║                                                 │                 ║
    ╚═════════════════════════════════════════════════╪═════════════════╝
                                                      │
                    ┌─────────────────────────────────┴───────────────┐
                    │                                                 │
                    ▼                                                 ▼
        ┌───────────────────┐                          ┌───────────────────┐
        │    ✓ SUCCESS      │                          │    ✗ STUCK        │
        │  Process exited   │                          │  Process running  │
        └─────────┬─────────┘                          └─────────┬─────────┘
                  │                                              │
                  │                                              │
                  ▼                                              ▼
    ┌─────────────────────────┐              ┌─────────────────────────────┐
    │  Ready for next         │              │  BLOCKING RESOURCES:        │
    │  scheduled trigger      │              │  ┌───────────────────────┐  │
    └─────────────────────────┘              │  │ • Open DB connections │  │
                                             │  │ • Active HTTP clients │  │
                                             │  │ • Background timers   │  │
                                             │  │ • Pending promises    │  │
                                             │  │ • Unawaited work      │  │
                                             │  └───────────────────────┘  │
                                             └──────────────┬──────────────┘
                                                            │
                                                            ▼
                              ┌──────────────────────────────────────────────┐
                              │            NEXT TRIGGER TIME                 │
                              │  ┌────────────────────────────────────────┐  │
                              │  │  Previous run still active?            │  │
                              │  │                                        │  │
                              │  │     YES ──▶ ⊘ NEW RUN SKIPPED          │  │
                              │  │                                        │  │
                              │  └────────────────────────────────────────┘  │
                              └──────────────────────────────────────────────┘

Behavioral constraints

Railway’s implementation introduces several operational boundaries:

  • All schedules are evaluated in UTC. Any workload that depends on local time boundaries must account for its own offset and daylight-saving behavior when defining its cron expression
  • Actual firing times may drift by a few minutes under platform load
  • The minimum interval between runs is five minutes
  • Only one execution may be active at a time
  • The system is designed for short-lived tasks, not long-running services such as web servers or chat bots

These constraints define the workflows that align cleanly with Railway’s cron model.

Configuring a cron job

To configure a scheduled task:

  1. Open the service and navigate to Settings
  2. Enter a valid cron expression in the Cron Schedule field
  3. Save the configuration

The cron expression determines the trigger schedule. The service itself is responsible for performing the work and terminating promptly.

Conclusion

Cron remains a precise and reliable mechanism for time-based execution when the workload fits its constraints. Its model is straightforward: evaluate a schedule, start a process, and allow that process to perform a discrete unit of work. Everything else, including correctness, idempotence, observability, concurrency control, and cleanup, belongs to the task itself. When these responsibilities are handled with care, cron provides a stable foundation for recurring operational tasks.

Railway builds on this model by supplying an execution environment that runs only when needed. A scheduled task consumes resources only for the duration of its work and then exits. This keeps recurring jobs efficient while preserving the essential behavior of cron.

As workloads increase in complexity, the distinction becomes clear. Cron is suitable for tasks that are short, bounded, and self-contained. A job scheduler or queue is suitable for tasks that require coordination, durability, or higher throughput. With these boundaries in mind, cron continues to serve as a dependable tool for periodic automation in production systems.