1 package db 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 ) 8 9 // Deadline defaults for the various database round-trips pgwatch performs. 10 // 11 // These are package-level vars rather than consts so tests can shrink them 12 // (e.g. to a few milliseconds) to exercise fault-injection paths quickly. 13 // 14 // `internal/db` is a leaf package — it MUST NOT import `internal/reaper` or 15 // `internal/sources`. Tests of the call sites shrink these vars locally and 16 // restore them on cleanup. 17 var ( 18 // MinFetchTimeout is the floor applied to fetch-path deadlines. Very 19 // short metric intervals still get a usable window to dial, authenticate, 20 // and return a meaningful error rather than aborting before the round-trip 21 // starts. 22 MinFetchTimeout = 30 * time.Second 23 24 // ChangeDetectionTimeout bounds the Detect*Changes family and the 25 // QueryMeasurements helper used by them. 26 ChangeDetectionTimeout = 60 * time.Second 27 28 // RuntimeInfoTimeout bounds each sub-query of FetchRuntimeInfo: 29 // version, platform discovery, approximate size, extensions, available 30 // extensions. 31 RuntimeInfoTimeout = 30 * time.Second 32 33 // ResolverTimeout bounds a single ResolveDatabasesFromPostgres call 34 // (pool creation + discovery query). 35 ResolverTimeout = 15 * time.Second 36 37 // PingTimeoutMargin is added on top of the configured ConnectTimeout when 38 // bounding the main-loop Ping gate. Default 5s + 5s = 10s total. 39 PingTimeoutMargin = 5 * time.Second 40 ) 41 42 // deadlineCause builds the canonical cause string attached to a derived 43 // context via context.WithTimeoutCause. The format "<op> deadline" is 44 // greppable and distinct per call site. 45 func deadlineCause(op string) error { 46 return fmt.Errorf("%s deadline", op) 47 } 48 49 // WithFetchTimeout returns a child of ctx whose deadline is 50 // max(interval, MinFetchTimeout). The op string is embedded in the context's 51 // cause so a context.DeadlineExceeded is distinguishable per call site. 52 // 53 // The cancel func MUST be called by the caller to release the timer once 54 // the work completes (or fails) — same convention as context.WithTimeout. 55 func WithFetchTimeout(ctx context.Context, op string, interval time.Duration) (context.Context, context.CancelFunc) { 56 return context.WithTimeoutCause(ctx, max(interval, MinFetchTimeout), deadlineCause(op)) 57 } 58 59 // WithOpTimeout returns a child of ctx with a fixed deadline of d. The op 60 // string is embedded in the context's cause so a context.DeadlineExceeded is 61 // distinguishable per call site. 62 // 63 // The cancel func MUST be called by the caller to release the timer. 64 func WithOpTimeout(ctx context.Context, op string, d time.Duration) (context.Context, context.CancelFunc) { 65 return context.WithTimeoutCause(ctx, d, deadlineCause(op)) 66 } 67