Cloud Scheduler vs Posthook: Cron vs Scheduling API

Compare Google Cloud Scheduler and Posthook for scheduled tasks on GCP. Cloud Scheduler handles recurring cron jobs. Posthook adds dynamic per-event scheduling with retries and anomaly detection — no 30-day cap, no 5-retry limit.

Last updated: March 24, 2026

Cloud Scheduler is a fully managed cron service on Google Cloud. It does recurring schedules well and it is very cheap. But it only does cron — there is no API for creating one-time jobs, no dynamic per-event scheduling, and no execution history UI.

Posthook is a managed scheduling and delivery service. You schedule a hook via API at runtime — when a user signs up, when a trial starts, when a payment fails — and Posthook delivers it to your endpoint at the right time with retries, delivery tracking, and anomaly detection.

The difference comes down to whether your schedules are fixed at deploy time or created dynamically based on application events. “Run a nightly report” is Cloud Scheduler’s job. “Send a reminder 48 hours after this user’s action” is Posthook’s. If you need both, they work together cleanly — but know the boundary.

At a glance

DimensionCloud SchedulerPosthook
Scheduling modelCron expressions only — fixed recurring schedulesDynamic API calls at runtime — one-time or recurring
One-time schedulingNot supportedFirst-class — postAt (UTC), postAtLocal + timezone (DST), postIn (relative delay)
Scheduling rangeMinimum 1-minute interval between runsAny future time via postAt/postAtLocal (no upper limit), relative delays up to 365 days via postIn
Delivery targetsHTTP/S, Pub/Sub topics, App Engine routesHTTP POST or WebSocket to any endpoint
Timezone / DSTIANA timezone on cron expressions, but DST transitions can cause skipped or double runspostAtLocal with explicit timezone and correct DST handling
Recurring schedulesCron expressionsSequences with calendar scheduling, onDays/onDates, dependency graphs, config-as-code
Retries0-5 retries (hard cap)Configurable — fixed, exponential, jitter, per-hook overrides at scheduling time
ObservabilityCloud Logging only — no execution history UIBuilt-in dashboard with per-hook delivery inspection and attempt history
AlertingCloud Monitoring (requires manual setup)Per-endpoint anomaly detection with email, Slack, and webhook alerts
Incident responseManual via Cloud Console or gcloud CLIBulk retry, cancel, or replay filtered by time range, endpoint, or sequence
Execution historyNone — must query Cloud LoggingFull attempt history with status codes, response bodies, and timing
Job/hook limits1,000 jobs per region (5,000 with quota increase)No hard cap on scheduled hooks
Cost3 free jobs per billing account, $0.10/job/month (paused jobs still bill)Free tier (1K hooks/mo), Launch $39/20K, Growth $99/100K
Vendor scopeGCP-onlyCloud-agnostic — any stack with an HTTP endpoint
Best fitFixed recurring cron jobs, Pub/Sub fan-out, App Engine cronDynamic per-event scheduling, one-time delayed delivery, timezone-aware scheduling with observability

How Cloud Scheduler works

Cloud Scheduler is Google’s fully managed cron service. You create a job with a cron expression, a target (HTTP, Pub/Sub, or App Engine), and an optional payload. Cloud Scheduler fires the job on the specified schedule. No infrastructure to manage, no servers to run.

This model does its narrow job well:

  • Simple setup. Create a job via Cloud Console, gcloud CLI, or Terraform. Specify a cron expression and a target. Done.
  • Native GCP integration. Pub/Sub topics, App Engine routes, and HTTP endpoints are all first-class targets. IAM service accounts handle authentication — OIDC or OAuth2 tokens can be attached to HTTP requests automatically.
  • Very cheap. Three free jobs per billing account. Beyond that, $0.10 per job per month. Ten recurring jobs cost $1/month. For simple recurring schedules, this is hard to beat.
  • Mature and stable. Narrow scope means fewer surprises. Cloud Scheduler does one thing and has done it reliably for years.
  • Familiar cron syntax. Standard cron expressions with an optional sixth field for seconds. Teams already comfortable with cron have no new syntax to learn.

The limitations are equally clear:

  • Cron-only. Every job requires a cron expression. There is no API for creating a one-time job that fires once and is done. If you need “do X at time T,” Cloud Scheduler cannot express it.
  • 5-retry hard cap. Jobs can be configured with 0 to 5 retries. You cannot increase this limit. If a target is down for longer than your retry window covers, the delivery is lost until the next cron cycle.
  • No execution history UI. Cloud Scheduler does not record whether a job ran successfully. To see execution outcomes, you must query Cloud Logging — which means setting up log-based metrics, log sinks, or querying logs manually. There is no dashboard showing “this job succeeded at 8:00, failed at 9:00, succeeded at 10:00.”
  • DST edge cases. Cloud Scheduler supports IANA timezones on cron expressions, but DST transitions can cause skipped runs or double runs depending on the transition direction and the scheduled time. Spring-forward transitions can skip a run; fall-back transitions can cause a double run.
  • 1,000 jobs per region. The default quota is 1,000 jobs per region. You can request an increase to 5,000, but this requires a quota request and approval. For teams with many recurring schedules or multi-tenant cron, this becomes a constraint.
  • Paused jobs still bill. A paused Cloud Scheduler job still counts toward your monthly charge. You pay $0.10/month for a job that is not running.

None of this makes Cloud Scheduler a bad tool. It makes it a cron service — purpose-built for fixed recurring schedules, not for dynamic per-event scheduling.

The Cloud Tasks gap

If Cloud Scheduler handles recurring cron and Cloud Tasks handles one-time delayed execution, the natural question is whether Cloud Tasks covers the dynamic scheduling gap. It partially does — but with a hard ceiling.

Cloud Tasks lets you schedule an HTTP request or App Engine task up to 30 days in the future. For short delays — “process this order in 5 minutes,” “send a confirmation email in 30 seconds” — Cloud Tasks works well. But the 30-day cap creates a dead zone:

  • Cloud Scheduler handles recurring cron. It cannot do one-time scheduling.
  • Cloud Tasks handles one-time delays up to 30 days. It cannot do recurring schedules. It cannot schedule beyond 30 days.
  • Neither covers “schedule an HTTP delivery at an arbitrary future time.”

If a trial expires in 45 days, Cloud Tasks cannot schedule it. If a subscription renewal fires in 6 months, Cloud Tasks cannot schedule it. The common workaround is a Cloud Scheduler cron job that polls a database for work — the same polling anti-pattern that teams adopt to compensate for cron’s inability to handle per-event timing.

Posthook covers the entire range with a single API: postAt and postAtLocal accept any future time with no upper limit, and postIn supports relative delays up to 365 days. One-time or recurring via Sequences. No 30-day cap, no polling workaround.

For a deeper comparison of Cloud Tasks and Posthook — including the 30-day workaround, per-queue vs per-hook retries, and observability differences — see Cloud Tasks vs Posthook.

How Posthook works

Posthook is a managed scheduling and delivery service. You schedule a hook via API — specifying a target endpoint, a delivery time, and an optional payload — and Posthook handles persistence, delivery, retries, and observability.

Delivery happens via HTTP POST or WebSocket. Your code runs in your own infrastructure, behind your own endpoint. Posthook stays out of your execution environment.

For a GCP developer, the dynamic scheduling model looks like this: a user starts a free trial and your Cloud Run service schedules an expiration check.

from posthook import Posthook

client = Posthook("phk_your_api_key")

# Trial expires in 14 days — check at 9am in the user's timezone
client.hooks.schedule(
    path="/hooks/expire-trial",
    data={"user_id": "usr_abc123", "trial_id": "trial_xyz"},
    post_at_local="2026-04-06T09:00:00",
    timezone="America/Chicago"
)

Your handler receives the delivery as an HTTP POST and decides what to do:

@app.route("/hooks/expire-trial", methods=["POST"])
def expire_trial():
    data = request.json["data"]
    trial = db.get_trial(data["trial_id"])

    # Handler checks state — act or skip
    if not trial or trial.status != "active":
        return jsonify({"skipped": True})

    db.expire_trial(trial.id)
    send_expiration_email(trial.user_id)

    return jsonify({"expired": True})

No cron job polling a database. No Cloud Tasks 30-day ceiling. Each event creates its own timer, and Posthook delivers it at the right time.

Key capabilities:

  • Time-native scheduling — exact UTC timestamps (postAt), local timezone with DST handling (postAtLocal + timezone), or relative delays (postIn). postAt and postAtLocal accept any future time with no upper limit; postIn supports delays up to 365 days.
  • Built-in anomaly detection — per-endpoint failure rate tracking against historical baselines, with alerts via email, Slack, or webhook when rates spike, and recovery notifications when they normalize.
  • Incident response — bulk retry, cancel, or replay failed hooks filtered by time range, endpoint key, or sequence ID. One API call recovers from an outage.
  • Async hooks for reliable long-running work — your endpoint returns 202 Accepted immediately, processes on its own timeline, and calls back via ack/nack URLs when done. Configurable timeouts up to 3 hours. Data exports, third-party API calls, report generation — work that takes longer than Cloud Scheduler’s attempt deadline completes reliably.
  • Per-hook retry overrides — individual hooks can override project-level retry settings at scheduling time, without changing defaults.
  • Sequences — recurring workflows with calendar scheduling (onDays/onDates, negative dates for end-of-month), dependency graphs, DST handling, and config-as-code via posthook.toml.
  • SDKsTypeScript, Python, and Go. Schedule from any service in your stack.

Tradeoffs

Where Cloud Scheduler wins

  • Dramatically cheaper for simple recurring jobs. Three free jobs, $0.10/job/month beyond that. If you have 10 recurring jobs, Cloud Scheduler costs $1/month. For fixed-cadence cron work, the economics are hard to beat.
  • Native Pub/Sub and App Engine targets. Cloud Scheduler can publish directly to Pub/Sub topics and route to App Engine services with IAM-managed authentication. Posthook cannot target Pub/Sub or App Engine — only HTTP endpoints and WebSocket connections.
  • Zero additional infrastructure. Cloud Scheduler is fully managed on GCP. If you are already on GCP, there is no new service to evaluate, no additional vendor relationship, no separate billing.
  • Native IAM integration. OIDC and OAuth2 tokens are attached to HTTP targets automatically via service accounts. No API keys to manage for GCP-internal communication.
  • Familiar cron syntax. Standard cron expressions that teams already know. No new scheduling API or SDK to learn for recurring work.

Where Posthook wins

  • Dynamic per-event scheduling. Cloud Scheduler is cron-only — every job needs a cron expression defined in advance. Posthook schedules at runtime based on application events. “Send a reminder 48 hours after signup” is one API call, not a cron job polling a database.
  • One-time scheduling at any future time. postAt and postAtLocal accept any future timestamp with no upper limit. postIn handles relative delays up to 365 days. Cloud Scheduler cannot create one-time jobs at all, and Cloud Tasks caps at 30 days.
  • Configurable retries without a hard cap. Cloud Scheduler’s retry limit is 5 attempts, period. Posthook supports configurable backoff (fixed, exponential, jitter) with per-hook overrides and no hard retry cap. If your target is down for an extended period, Posthook keeps retrying.
  • Built-in observability and anomaly detection. Dashboard with per-hook delivery inspection, attempt history, status codes, and response bodies. Per-endpoint anomaly detection alerts you when failure rates spike. Cloud Scheduler has no execution history UI — you must query Cloud Logging to see what happened.
  • Incident response tooling. One API call retries all failed hooks in a time range. Cloud Scheduler has no built-in replay or bulk retry — recovery after an outage means manually re-triggering jobs through Cloud Console or gcloud.
  • Timezone-aware scheduling with correct DST handling. postAtLocal with an IANA timezone handles DST transitions correctly. Cloud Scheduler supports IANA timezones on cron expressions, but DST transitions can cause skipped or double runs.
  • Sequences for recurring HTTP work. For HTTP targets, Posthook Sequences fully replace Cloud Scheduler’s cron — with calendar scheduling (onDays/onDates), dependency graphs between steps, per-step retry overrides, and config-as-code with diff and apply. Cloud Scheduler has cron expressions and nothing more.
  • Cloud-agnostic. Posthook works with any stack — GCP, AWS, Azure, Vercel, bare metal. Cloud Scheduler is GCP-only.
  • At-least-once delivery. Posthook uses at-least-once delivery — handlers should be idempotent. Duplicates are rare but possible.

When to use both

Cloud Scheduler and Posthook complement each other on GCP. The boundary is straightforward: Cloud Scheduler for targets Posthook cannot reach, Posthook for scheduling patterns Cloud Scheduler cannot express.

Keep Cloud Scheduler for:

  • Pub/Sub fan-out. If your recurring job publishes to a Pub/Sub topic that fans out to multiple subscribers, Cloud Scheduler is the right tool. Posthook cannot publish to Pub/Sub.
  • App Engine routes. If your recurring job targets an App Engine service with IAM-managed authentication, Cloud Scheduler handles this natively. Posthook cannot target App Engine routes directly.
  • Simple, cheap recurring cron. A nightly database cleanup or hourly cache warm-up that targets Pub/Sub or App Engine — Cloud Scheduler costs $0.10/month and requires no additional tooling.

Use Posthook for:

  • Dynamic per-event scheduling. User reminders, trial expirations, payment retries, delayed follow-ups — anything where the schedule is determined at runtime by application events.
  • One-time scheduling beyond 30 days. Cloud Tasks caps at 30 days. Posthook handles any future time with no upper limit.
  • Recurring HTTP targets with richer scheduling. For HTTP targets specifically, Posthook Sequences replace Cloud Scheduler’s cron with calendar scheduling, dependency graphs, DST handling, and per-step retry overrides.
  • Scheduling that needs observability. If you want delivery tracking, attempt history, anomaly detection, and incident response tooling, Posthook provides this out of the box.

Cloud Scheduler can also trigger Posthook via HTTP — useful if you want a cron cadence to kick off dynamic scheduling flows. For example, a Cloud Scheduler job fires hourly and hits a Posthook endpoint that creates per-user reminders based on the latest application state.

When to choose each

Choose Cloud Scheduler when:

  • You need simple recurring cron jobs on GCP
  • The schedule is fixed and known at deploy time — nightly cleanup, hourly report, periodic sync
  • Your targets are Pub/Sub topics or App Engine routes
  • Cost is the primary concern and volume is low
  • You are deep in GCP and want native IAM integration
  • You do not need execution history or delivery observability beyond Cloud Logging
  • 5 retries is sufficient for your failure scenarios

Choose Posthook when:

  • The primary problem is dynamic, per-event scheduling — “send a reminder 24 hours after signup,” “expire this trial in 14 days,” “retry this payment next Tuesday”
  • You need one-time schedules at arbitrary future times beyond Cloud Tasks’ 30-day cap
  • You need recurring HTTP schedules with more control than cron — Posthook Sequences offer calendar scheduling, dependency graphs, and per-step retry overrides
  • You want managed delivery with built-in observability, anomaly detection, and alerting without assembling Cloud Monitoring dashboards
  • You need timezone-aware scheduling with correct DST handling
  • You need more than 5 retries per delivery
  • You want incident response tooling — bulk replay, filtering, one-call recovery
  • Your services span multiple clouds or platforms, not just GCP

Frequently asked questions

Ready to get started?

Create your free account and start scheduling hooks in minutes. No credit card required.