Skip to content

feat: add running-hours keep-warm windows and timezone support#907

Merged
acouvreur merged 3 commits into
mainfrom
feat/running-hours-guide-example
May 14, 2026
Merged

feat: add running-hours keep-warm windows and timezone support#907
acouvreur merged 3 commits into
mainfrom
feat/running-hours-guide-example

Conversation

@acouvreur

@acouvreur acouvreur commented May 14, 2026

Copy link
Copy Markdown
Member

Summary

Closes #292

This PR adds daily running-hours support so Sablier can proactively keep selected instances warm during configured time windows.

It also includes:

  • timezone support improvements for container deployments
  • updated documentation with operator-focused guidance
  • tests for parsing/window behavior and session-expiration extension logic
  • a runnable example in examples/running-hours

User Guide

What is new

You can now set the sablier.running-hours label on managed instances:

labels:
  - "sablier.enable=true"
  - "sablier.group=myapp"
  - "sablier.running-hours=09:00-18:00"

Behavior:

  • At startup and then periodically, Sablier reconciles managed instances.
  • If current local time is inside the running-hours window, Sablier ensures the instance is started.
  • While in-window, request-triggered session expiration is extended up to the window end so the instance does not stop mid-window.
  • Outside the window, normal session expiration behavior applies.

Supported format:

  • HH:MM-HH:MM (24-hour clock)
  • overnight windows are supported, for example 22:00-06:00

Invalid values are ignored with a warning.

Timezone behavior

Running-hours are evaluated in the process local timezone.

This PR ensures timezone support for container deployments by:

  • embedding tz database support in the binary (time/tzdata)
  • setting a default TZ=UTC in the Docker image

Override timezone as needed at runtime, for example:

docker run -e TZ=Europe/Paris ...

Example added

A new runnable example is available in examples/running-hours.

It contains:

  • compose.yml
  • Makefile
  • README.md walkthrough

The example demonstrates:

  • configuring RUNNING_HOURS
  • configuring TZ
  • triggering requests and observing keep-warm behavior in logs

Implementation Notes

  • Added running-hours parsing and window evaluation helpers.
  • Added a periodic reconciliation watcher for running-hours.
  • Extended InstanceRequest expiration logic to respect active running-hours windows.
  • Extended instance label parsing to include sablier.running-hours.

Tests

Executed:

  • go test ./pkg/sablier/...

Added tests cover:

  • parsing valid/invalid running-hours strings
  • day and overnight window calculations
  • expiration extension while inside running-hours
  • no extension outside running-hours

Changed files

  • pkg/sablier/running_hours.go
  • pkg/sablier/running_hours_watch.go
  • pkg/sablier/instance.go
  • pkg/sablier/instance_request.go
  • pkg/sablier/running_hours_test.go
  • pkg/sablier/instance_request_running_hours_test.go
  • pkg/sablier/instance_test.go
  • pkg/sabliercmd/start.go
  • cmd/sablier/cmd.go
  • build/Dockerfile
  • docs/configuration.md
  • examples/running-hours/*

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label May 14, 2026
@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown

Test Results

✅ All tests passed! | 329 tests in 73.894s

View HTML Test Report

@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown
┌────────────────────────────────────────────────────────────────────────────────┐
│ Diff between sablier and sablier                                               │
├─────────┬──────────────────────────────────────┬──────────┬──────────┬─────────┤
│ PERCENT │ NAME                                 │ OLD SIZE │ NEW SIZE │ DIFF    │
├─────────┼──────────────────────────────────────┼──────────┼──────────┼─────────┤
│ +9.74%  │ github.com/sablierapp/sablier        │ 325 kB   │ 357 kB   │ +32 kB  │
│ +1.69%  │ time                                 │ 157 kB   │ 160 kB   │ +2.7 kB │
│ +0.13%  │ text/template                        │ 292 kB   │ 292 kB   │ +389 B  │
│ +0.04%  │ <autogenerated>                      │ 948 kB   │ 949 kB   │ +355 B  │
│ +0.00%  │ github.com/google/gnostic-models     │ 1.6 MB   │ 1.6 MB   │ +10 B   │
│ +0.00%  │ k8s.io/client-go                     │ 14 MB    │ 14 MB    │ +10 B   │
│ +0.00%  │ k8s.io/api                           │ 17 MB    │ 17 MB    │ +2 B    │
│ +0.00%  │ github.com/emicklei/go-restful/v3    │ 133 kB   │ 133 kB   │ +1 B    │
│ +0.00%  │ k8s.io/utils                         │ 32 kB    │ 32 kB    │ +1 B    │
│ -0.00%  │ github.com/spf13/pflag               │ 302 kB   │ 302 kB   │ -2 B    │
│ -0.00%  │ html                                 │ 136 kB   │ 136 kB   │ -2 B    │
│ -0.00%  │ github.com/moby/moby/api             │ 149 kB   │ 149 kB   │ -2 B    │
│ -0.00%  │ os                                   │ 210 kB   │ 210 kB   │ -2 B    │
│ -0.01%  │ sort                                 │ 29 kB    │ 29 kB    │ -2 B    │
│ -0.00%  │ k8s.io/apimachinery                  │ 1.8 MB   │ 1.8 MB   │ -4 B    │
│ -0.00%  │ github.com/quic-go/quic-go           │ 1.3 MB   │ 1.3 MB   │ -4 B    │
│ -0.00%  │ google.golang.org/protobuf           │ 1.7 MB   │ 1.7 MB   │ -4 B    │
│ -0.00%  │ go.mongodb.org/mongo-driver/v2       │ 672 kB   │ 672 kB   │ -4 B    │
│ -0.01%  │ github.com/prometheus/common         │ 68 kB    │ 68 kB    │ -4 B    │
│ -0.01%  │ unique                               │ 34 kB    │ 34 kB    │ -4 B    │
│ -0.00%  │ go.opentelemetry.io/otel             │ 407 kB   │ 407 kB   │ -6 B    │
│ -0.00%  │ sigs.k8s.io/structured-merge-diff/v6 │ 275 kB   │ 275 kB   │ -6 B    │
│ -0.05%  │ embed                                │ 12 kB    │ 12 kB    │ -6 B    │
│ -0.00%  │ golang.org/x/text                    │ 162 kB   │ 162 kB   │ -7 B    │
│ -0.06%  │ github.com/spf13/afero               │ 21 kB    │ 21 kB    │ -12 B   │
│ -0.00%  │ golang.org/x/net                     │ 789 kB   │ 789 kB   │ -16 B   │
│ -0.00%  │ net                                  │ 1.7 MB   │ 1.7 MB   │ -26 B   │
│ -0.00%  │ crypto                               │ 1.9 MB   │ 1.9 MB   │ -52 B   │
├─────────┼──────────────────────────────────────┼──────────┼──────────┼─────────┤
│ +19.18% │ .rodata                              │ 2.1 MB   │ 2.5 MB   │ +409 kB │
│ +0.01%  │ .noptrdata                           │ 451 kB   │ 451 kB   │ +32 B   │
├─────────┼──────────────────────────────────────┼──────────┼──────────┼─────────┤
│ +0.76%  │ sablier                              │ 59 MB    │ 59 MB    │ +446 kB │
│         │ sablier                              │          │          │         │
└─────────┴──────────────────────────────────────┴──────────┴──────────┴─────────┘

@sonarqubecloud

Copy link
Copy Markdown

@acouvreur acouvreur merged commit ed9c611 into main May 14, 2026
8 checks passed
@acouvreur acouvreur deleted the feat/running-hours-guide-example branch May 14, 2026 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature: add ability to wake up containers automatically on specific hours

1 participant