Manual Jobs, Delayed Jobs, Scheduled Pipelines, Rollbacks, Freeze Windows, and Release Controls: Configuration, Design Choices, and Tradeoffs
Choose the smallest deterministic set of manual, timed, schedule, freeze, freshness, and rollback controls for a maintainable production release architecture.
Learning objectives
- Choose between manual jobs and protected-environment approvals without conflating them.
- Choose between delayed execution, GitLab schedules, and external schedulers based on ownership and failure domains.
- Design freeze and emergency-exception policy that remains auditable and recoverable.
- Balance stale-deployment prevention with deliberate rollback.
- Justify release controls using security, reliability, maintainability, compatibility, performance, and cost.
manual_confirmation, delayed jobs with
start_in, pipeline schedules, deployment freeze periods /
CI_DEPLOY_FREEZE, environment/deployment history, the
project setting that prevents outdated deployment jobs, and
rollback/retry controls are available on GitLab Free/Premium/Ultimate
across GitLab.com, Self-Managed, and Dedicated. Protected environments
and deployment approvals—the fine-grained “only these people may
deploy” layer—remain Premium/Ultimate. The mandatory chapter path uses
only a disposable project, synthetic artifacts/environments, and tiny
jobs. No production endpoint, cloud account, paid tier, runner
registration, real credential, or release publication is required.
1. Design principle: make the normal safe path easier than the bypass
A release control fails socially before it fails technically when teams perceive it as arbitrary friction. Good controls are predictable: the job says why it is blocked, the right actor can proceed without administrator intervention, stale paths cannot race, exceptions are documented, and rollback does not require rebuilding half the world.
Do not maximize the number of gates. Minimize the number of ambiguous state transitions.
2. Manual gate versus protected-environment approval
| Dimension | Manual job (Free) | Protected environment / deployment approval (Premium/Ultimate) |
|---|---|---|
| Primary function | Requires someone to start a job. | Restricts deployers and can require designated deployment approvers. |
| Authorization granularity | Actor needs permission to merge to assigned branch; branch/project permissions matter. | Allowed-to-deploy list / approval rules can narrow environment authority. |
| Accidental-click defense | Add manual_confirmation. |
Approval + job execution remain separate actions. |
| Separation of duties | Weak if same broad project role can merge and run deploy. | Stronger when different approved roles/groups govern environment. |
| Free course path | Fully hands-on. | Fixture/read-only design exercise. |
A blocking manual job can be a useful operational gate, but it should not be sold as compliance-grade separation if the same broad role can change the pipeline, merge the code, and run the deployment.
3. GitLab schedule versus external scheduler
| Question | GitLab pipeline schedule | External scheduler / orchestrator |
|---|---|---|
| Where does cron live? | Inside GitLab project. | Outside GitLab. |
| Execution identity | Schedule owner; manual Run uses triggering user. | External service identity/token invokes GitLab or another system. |
| Pipeline source | schedule. |
Often API/trigger/parent source depending on mechanism. |
| Operational coupling | Simple for GitLab-native maintenance and validation. | Useful when one enterprise scheduler coordinates many systems. |
| Credential burden | No external trigger credential required for normal schedule. | Requires secure external authentication and rotation. |
| Failure domain | GitLab availability/schedule owner/ref permissions. | External scheduler + integration + GitLab. |
Use GitLab schedules when the job belongs naturally to the repository and pipeline. Use an external scheduler when the release window is a cross-system orchestration problem—but then make the external identity and API idempotence explicit.
4. Delay inside pipeline versus scheduled pipeline
Choose start_in when the delay is causally tied to one
pipeline, such as “wait 10 minutes after staging verification.”
Choose a schedule when the requirement is calendar recurrence, such
as “run at 03:17 UTC every day.” A delayed job has a maximum delay
of one week and can become stale while it waits.
A useful rule: if you would be upset when the original pipeline is canceled, the delay probably belongs to that pipeline. If you still want the event next Tuesday regardless of this pipeline, use a schedule.
5. Freeze window versus emergency exception
A freeze should encode the default behavior during a known risky period—not silently grant or revoke business authority. Design three things separately:
-
Detection: GitLab freeze period exposes
CI_DEPLOY_FREEZE. - Default action: deployment is excluded, blocked, or converted to manual.
- Exception path: who may proceed, what incident/change reference is required, and what post-release review occurs.
Because protected-environment fine-grained deployer rules are paid, the Free mandatory pattern can model the exception decision but cannot claim equivalent separation of duties. In real Free deployments, target-system IAM and a separate deployment project can materially reduce blast radius.
6. Prevent outdated deployments versus rollback freedom
The stale-deployment setting protects forward progress. Rollback intentionally moves to older application state. Those goals conflict unless the process distinguishes accidental old work from deliberate recovery.
| Policy choice | Benefit | Risk / mitigation |
|---|---|---|
| Prevent outdated deployments ON | Stops old queued/manual jobs from overwriting later deployment. | Rollback via retry may be restricted; use an explicit new recovery pipeline to previous commit/artifact. |
| Rollback job retries allowed | Fast operator recovery. | A retry can weaken freshness policy; disable in sensitive projects and require a new recovery pipeline. |
resource_group serialization |
Prevents simultaneous environment mutation. | Queue order may still matter; inspect process mode and deployment freshness. |
7. Rebuild rollback versus immutable-artifact rollback
Rebuilding source is cheaper to design initially because every pipeline “knows how to build.” But it weakens forensic confidence: upstream packages, container bases, compiler versions, or external repositories may have changed. An immutable-artifact promotion model costs storage and retention planning but lets rollback mean “deploy digest X again.”
For high-assurance releases, record source SHA + build pipeline ID + artifact digest + deployment job ID + environment deployment ID. The rollback request points to that evidence bundle.
8. Manual variables versus typed inputs
Manual CI/CD variables are flexible but can override pipeline
values, are expanded, and may be visible to project members who can
rerun the job. Prefer job/pipeline inputs for non-secret operator
choices such as strategy=blue-green or
target=staging. Secrets should come from
protected/scoped variables or external identity-based retrieval, not
a form field.
9. Who can cancel or supersede a release path?
On Free, Developers/Maintainers/Owners generally can cancel pipelines/jobs under default settings; Premium/Ultimate can restrict cancellation roles. Operationally, cancellation is part of release authority. If a stale delayed deployment must be canceled, record the actor and reason. Do not design an emergency path that requires deleting history.
10. Time controls can consume capacity in surprising ways
Delayed jobs avoid immediately occupying a runner slot, but the pipeline remains active and may block later stages. Schedules can create bursts at common cron times. GitLab.com hosted compute quotas and Self-Managed runner capacity are external constraints: spread non-urgent schedules and keep maintenance jobs small. A freeze may reduce deployment jobs but should not accidentally duplicate pipelines through broad schedule/push rules.
11. Worked decision table
| Scenario | Recommended controls | Why |
|---|---|---|
| Small team, staging deploy after tests | Blocking manual job + confirmation + artifact checksum. | Free, visible, adequate when same team owns staging. |
| Production with separation-of-duties requirement | Protected environment + deployment approvals + protected ref + target IAM + immutable artifact. | Manual button alone does not prove independent authorization. |
| Nightly dependency validation | Pipeline schedule with typed inputs; small runner footprint. | Independent of code pushes; owner/ref are auditable. |
| Canary 10 minutes after staging | Delayed job tied to same pipeline + stale-deploy prevention + resource group. | Delay is causally connected to this release. |
| Holiday production freeze | Freeze period + rules that block/convert deploy + documented emergency path. | Time signal plus explicit policy; freeze is not IAM. |
| Critical rollback | New recovery pipeline to previous known commit/artifact; preserve failed/new deployment records. | Restores known identity without history rewrite. |
12. Minimal Free-compatible release policy
1. Every release job records pipeline ID, commit SHA, artifact checksum, and environment.
2. Default production-like deployment is blocking manual with explicit confirmation.
3. Manual jobs never accept real credentials as ad-hoc variables.
4. Recurring work uses owned pipeline schedules; stale owners are reviewed.
5. Freeze windows change normal deployment behavior but do not grant exceptions.
6. One resource_group serializes one mutable environment.
7. Prevent outdated deployment jobs is enabled for the disposable production-like environment.
8. Rollback is a new controlled deployment of known artifact identity.
9. Every exception records actor, reason, and post-deploy verification.
10. Cleanup deletes only disposable schedules/freeze periods/refs by captured ID.
13. Anti-patterns
- “Play button = approval.” It proves someone with required branch permission started a job; it may not prove independent review.
- “Freeze = security boundary.” It is a time-policy signal. Authorization lives elsewhere.
- “Schedule = service account.” It is owned by a user and inherits that user’s permissions.
- “Delay = fresh deployment.” The original pipeline can age while waiting.
- “Retry = rollback.” Recovery is only trustworthy if the intended commit/artifact identity is proven.
Knowledge check
When should you prefer a GitLab schedule over
start_in?
When the requirement is recurring calendar-time pipeline creation independent of one existing pipeline.
What extra security property does a protected environment add over a normal manual job?
It can narrow who is allowed to deploy to that environment; deployment approvals can add designated approvers. These are Premium/Ultimate.
Why can “prevent outdated deployment jobs” complicate rollback?
A deliberate old-state deployment resembles a stale deployment. Use a controlled new recovery pipeline/known artifact rather than weakening freshness globally.
What is the operational risk of schedule ownership?
If the owner is blocked/removed or loses protected-ref permission, the schedule can become inactive or lose intended access.
Why is a freeze exception a governance workflow, not just
when: manual?
You still need authorized actors, a reason/change record, target IAM, evidence, and post-release verification.
Summary
Choose release controls by the state they govern: manual jobs for human start, protected environments/approvals for deploy authorization, delays for causal waiting, schedules for recurrence, freezes for time-policy, stale-deployment settings for freshness, and immutable-artifact recovery for rollback. The smallest deterministic set is usually safer than a pile of overlapping gates.
Official references
- GitLab Docs — Control how jobs run
- GitLab Docs — CI/CD YAML syntax reference
- GitLab Docs — Scheduled pipelines
- GitLab Docs — Pipeline schedules API
- GitLab Docs — Deployment safety
- GitLab Docs — Deployments
- GitLab Docs — Environments
- GitLab Docs — Freeze Periods API
- GitLab Docs — Predefined CI/CD variables
- GitLab Docs — Pipeline settings
- GitLab Docs — Pipelines
- GitLab Docs — Job troubleshooting
- GitLab Docs — Resource groups
- GitLab Docs — Protected environments
- GitLab Docs — Deployment approvals
- GitLab Docs — Job token
- GitLab Docs — Roles and permissions
- GitLab 19.3 — What’s new
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.