feat(admin): lapse sweep and the four renewal notices
Hourly sweep marks expired Free instances lapsed and sends at most one notice per instance per pass, most urgent first, recorded on the document so a restart cannot re-send. Deletion warnings are suppressed when the reaper is off. Promising a deletion that will never happen is a lie, and a scarier one than silence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -26,6 +27,7 @@ type Config struct {
|
||||
AllowedOrigins []string
|
||||
TrustProxy bool
|
||||
Addr string
|
||||
ReapAfter time.Duration
|
||||
|
||||
SMTPHost string
|
||||
SMTPPort string
|
||||
@@ -108,6 +110,18 @@ func Load() (Config, error) {
|
||||
c.AllowedOrigins = append(c.AllowedOrigins, o)
|
||||
}
|
||||
}
|
||||
|
||||
// Mirrors the control plane's FREE_INSTANCE_REAP_AFTER so notice emails can
|
||||
// name the real deletion date. An unparseable value is refused rather than
|
||||
// silently treated as "off": a typo here would quietly stop every deletion
|
||||
// warning while the control plane still deletes.
|
||||
if v := os.Getenv("FREE_INSTANCE_REAP_AFTER"); v != "" {
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("FREE_INSTANCE_REAP_AFTER %q: %w", v, err)
|
||||
}
|
||||
c.ReapAfter = d
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user