### Cron Example Usage Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/cron.md Demonstrates how to parse a cron expression, get the current time, calculate the next execution time, and print the duration until the next execution. ```go schedule, _ := ParseCron("0 14 * * *") // Every day at 2 PM now := time.Now() next := schedule.Next(now) duration := time.Until(next) fmt.Printf("Next execution in %v\n", duration) ``` -------------------------------- ### Run Function Example Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Demonstrates how to configure RunConfig and an APIClient to execute a command and send pings. The exit code is then used to terminate the process. ```go cfg := RunConfig{ OnSuccess: PingTypeSuccess, OnNonzeroExit: PingTypeExitCode, OnExecFail: PingTypeFail, } client := &APIClient{ BaseURL: "https://hc-ping.com", Retries: 2, Client: &http.Client{Timeout: 5 * time.Second}, } exitCode := Run([]string{"bash", "-c", "echo ok"}, cfg, "uuid-123", client) os.Exit(exitCode) ``` -------------------------------- ### Send Start Ping Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/apiclient.md Sends a start ping for a check handle to signal the beginning of command execution. Requires an initialized APIClient and a valid handle. ```go icfg, err := client.PingStart("8116e449-d71c-4112-8f5d-a66f60902091", PingParams{}) ``` -------------------------------- ### Install Runitor Locally Source: https://github.com/bdd/runitor/blob/main/README.md Use this command to install the latest version of runitor locally if you have Go 1.19 or newer installed. The binary will be placed in your Go bin directory. ```bash go install bdd.fi/x/runitor/cmd/runitor@latest ``` -------------------------------- ### Exec Function Example Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Shows how to use the Exec function to run a command, capturing its output into a ring buffer. It includes error handling for execution failures. ```go out := NewRingBuffer(10000) exitCode, err := Exec([]string{"sh", "-c", "date"}, out, out) if err != nil && exitCode != 0 { fmt.Printf("Failed with exit code %d: %v\n", exitCode, err) } ``` -------------------------------- ### PingStart Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/apiclient.md Sends a start ping for the check handle to signal the beginning of command execution. It returns an InstanceConfig with server configuration or an error if the request fails. ```APIDOC ## PingStart ### Description Sends a start ping for the check handle to signal the beginning of command execution. ### Method POST (inferred from context, actual method not specified) ### Endpoint (Not specified in source) ### Parameters #### Path Parameters - **handle** (string) - Required - Check UUID or formatted key/slug handle #### Query Parameters (Not specified in source) #### Request Body - **params** (PingParams) - Required - Ping parameters (RunId, Create flag) ### Request Example ```go client := &APIClient{ BaseURL: "https://hc-ping.com", Retries: 2, Client: &http.Client{Timeout: 5 * time.Second}, } icfg, err := client.PingStart("8116e449-d71c-4112-8f5d-a66f60902091", PingParams{}) if err != nil { log.Fatal(err) } ``` ### Response #### Success Response - **InstanceConfig** (*InstanceConfig) - Server configuration #### Response Example (Not specified in source) ``` -------------------------------- ### Full Go Integration Example Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Demonstrates a complete integration with Runitor using the Go client. This includes creating an API client, preparing execution configuration, and running a command with reporting. ```go package main import ( "io" "net/http" "time" . "bdd.fi/x/runitor/internal" ) func main() { // Create API client client := &APIClient{ BaseURL: "https://hc-ping.com", Retries: 2, Client: &http.Client{ Transport: NewDefaultTransportWithResumption(), Timeout: 5 * time.Second, }, UserAgent: "my-app/1.0", } // Prepare execution config cfg := RunConfig{ OnSuccess: PingTypeSuccess, OnNonzeroExit: PingTypeExitCode, OnExecFail: PingTypeFail, PingBodyLimit: 10000, } // Execute and report exitCode := Run( []string{"/bin/backup.sh"}, cfg, "my-check-uuid", client, ) } ``` -------------------------------- ### InstanceConfig Usage Example Source: https://github.com/bdd/runitor/blob/main/_autodocs/types.md Demonstrates how to populate InstanceConfig from an HTTP response and conditionally use the PingBodyLimit. The limit is capped at 10,000,000 bytes. ```go icfg := &InstanceConfig{} icfg.FromResponse(resp) if limit, ok := icfg.PingBodyLimit.Get(); ok { bufferSize = min(limit, 10_000_000) } ``` -------------------------------- ### Example: Using Optional with Ping Body Limits Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Illustrates fetching a server-recommended limit for a buffer size, using Optional to handle cases where the limit is not provided. ```go // Create client and send start ping client := &APIClient{BaseURL: "https://hc-ping.com"} icfg, _ := client.PingStart(handle, params) // Check server's recommended limit if serverLimit, ok := icfg.PingBodyLimit.Get(); ok { // Server returned a limit bufferSize := min(serverLimit, 10_000_000) } else { // Server didn't return a limit; use default bufferSize := 10_000 } buffer := NewRingBuffer(bufferSize) ``` -------------------------------- ### APIClient Initialization with Custom Transport Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/apiclient.md Example of initializing an APIClient with a custom http.Client that uses a transport with TLS session resumption enabled. ```go client := &APIClient{ Client: &http.Client{ Transport: NewDefaultTransportWithResumption(), Timeout: 5 * time.Second, }, } ``` -------------------------------- ### Runitor Command Line Examples Source: https://github.com/bdd/runitor/blob/main/_autodocs/README.md Demonstrates one-shot, periodic, and scheduled execution of commands using the runitor CLI. Use these for immediate or recurring task automation. ```bash # One-shot: run once and exit runitor -uuid 8116e449-d71c-4112-8f5d-a66f60902091 -- /bin/backup.sh ``` ```bash # Periodic: run every 2 hours and 24 minutes runitor -every 2h24m -slug backup -ping-key mykey -- /backup.sh ``` ```bash # Scheduled: run at 2 AM and 2 PM daily runitor -at "0 2,14 * * *" -slug backup -ping-key mykey -- /backup.sh ``` -------------------------------- ### ParseCron Examples Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/cron.md Demonstrates various cron expressions that can be parsed by the ParseCron function, including common scheduling patterns. ```go // Every 5 minutes cron, err := ParseCron("*/5 * * * *") ``` ```go // Every morning at 2 AM cron, err := ParseCron("0 2 * * *") ``` ```go // Mondays at 9 AM cron, err := ParseCron("0 9 * * 1") ``` ```go // 1st and 15th of each month cron, err := ParseCron("0 0 1,15 * *") ``` -------------------------------- ### Configure APIClient in Go Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Example of initializing an APIClient in Go with various configuration options. Ensure BaseURL and Client are provided. Other fields like Retries, UserAgent, Backoff, and ReqHeaders are optional. ```go client := &APIClient{ BaseURL: "https://hc-ping.com", // Required Retries: 2, // Transient error retries Client: &http.Client{...}, // Embedded http.Client UserAgent: "runitor/v1.0 (linux-amd64; +https://bdd.fi/x/runitor)", Backoff: 0, // Linear backoff unit (0 = 1 second default) ReqHeaders: map[string]string{ "Authorization": "Bearer token", }, } ``` -------------------------------- ### Database Backup with Runitor Source: https://github.com/bdd/runitor/blob/main/README.md Automate daily database backups using cron-like scheduling. This example runs the backup script every day at 2 a.m. and 2 p.m. ```bash # Run the backup script every day at 2 a.m and 2 p.m. runitor -slug db-backup \ -at "00 02,14 * * *" -- \ /script/db-backup ``` -------------------------------- ### RingBuffer Example Usage Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Demonstrates writing data to a RingBuffer, including exceeding its capacity and checking the wrapped status. Use this to understand how overwriting affects buffer state. ```go buf := NewRingBuffer(100) buf.Write([]byte("a")) // written=1, wrapped=false buf.Write(make([]byte, 150)) // written=151, wrapped=true (overwrote 51 bytes) if buf.Wrapped() { written := buf.Written() retained := buf.Cap() fmt.Printf("Truncated from %d to %d bytes\n", written, retained) } ``` -------------------------------- ### Get Method Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Retrieves the wrapped value and a boolean indicating its presence. The boolean is true if the Optional is defined. ```go func (o Optional[T]) Get() (T, bool) ``` ```go val, ok := opt.Get() if ok { fmt.Printf("Limit is %d bytes\n", val) } else { fmt.Println("No limit set") } ``` -------------------------------- ### Repository Maintenance with Runitor Source: https://github.com/bdd/runitor/blob/main/README.md Schedule repository maintenance tasks to run at specified intervals. This example runs the maintenance script 10 times a day using a per-project ping key and check slugs. ```bash # Run the maintenance script 10 times a day (24h/10 = 2h 24m) # (Using per-project ping key, and check slugs.) export PING_KEY=file:/run/secrets/hc_prod_pingkey runitor -slug git-repo-maintenance \ -every 2h24m -- \ /script/git-maint ``` -------------------------------- ### Linear Retry Backoff Strategy Source: https://github.com/bdd/runitor/blob/main/_autodocs/README.md Describes the linear backoff strategy for retrying transient failures. Includes example wait times and default max attempts. ```text Try 1: immediate Try 2: wait 1s (1 × backoff unit) Try 3: wait 2s (2 × backoff units) Fail: error after max tries ``` -------------------------------- ### Ping Configuration Flags Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Flags to customize the ping behavior, including start pings, run IDs, output inclusion, and success/failure notifications. ```APIDOC ## Ping Configuration Flags ### `-no-start-ping` Don't send a start ping when command execution begins. ### `-no-run-id` Don't generate and include a unique run ID (UUID) with each ping. ### `-no-output-in-ping` Don't attach command output to success and failure pings. ### `-on-success ` Ping type to send when command exits with code 0. **Options:** `exit-code`, `success`, `fail`, `log` **Default:** `success` **Example:** ```bash # Log successful runs without signaling success runitor -on-success log -uuid abc123 -- cmd ``` ### `-on-nonzero-exit ` Ping type to send when command exits with non-zero code. **Options:** `exit-code`, `success`, `fail`, `log` **Default:** `exit-code` **Example:** ```bash # Explicitly fail on non-zero exit runitor -on-nonzero-exit fail -uuid abc123 -- cmd ``` ### `-on-exec-fail ` Ping type to send when runitor cannot execute the command (e.g., command not found). **Options:** `exit-code`, `success`, `fail`, `log` **Default:** `fail` ### `-create` Create a new check in the project if the slug is not found (requires `-slug` and `-ping-key`). **Example:** ```bash runitor -create -slug new-check -ping-key mykey -- cmd ``` ``` -------------------------------- ### Cross-Compile Runitor Source: https://github.com/bdd/runitor/blob/main/README.md Build runitor for a different operating system and architecture by setting the GOOS and GOARCH environment variables before running 'go install'. The binary will be placed in a subdirectory reflecting the target platform. ```bash GOOS=plan9 GOARCH=arm go install bdd.fi/x/runitor/cmd/runitor@latest ``` -------------------------------- ### Pinger Interface Definition Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/apiclient.md Defines the Pinger interface, outlining methods for pinging an instance, including starting, logging, success, failure, and exit code reporting. ```go type Pinger interface { PingStart(handle string, params PingParams) (*InstanceConfig, error) PingLog(handle string, params PingParams, body io.ReadSeeker) (*InstanceConfig, error) PingSuccess(handle string, params PingParams, body io.ReadSeeker) (*InstanceConfig, error) PingFail(handle string, params PingParams, body io.ReadSeeker) (*InstanceConfig, error) PingExitCode(handle string, params PingParams, exitCode int, body io.ReadSeeker) (*InstanceConfig, error) } ``` -------------------------------- ### Retrieve Value from Flag or Environment Variable Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Use this function to get configuration values from command-line flags or environment variables. It supports reading values from files by prefixing the flag with 'file:'. File contents are trimmed of whitespace. ```go func FromFlagOrEnv(flg string, envvars []string) string ``` ```go uuid := FromFlagOrEnv("", []string{"CHECK_UUID"}) if uuid == "" { log.Fatal("Must set CHECK_UUID") } // With file indirection pingKey := FromFlagOrEnv("file:/run/secrets/ping-key", []string{}) ``` -------------------------------- ### Handle Empty Secret File Error Source: https://github.com/bdd/runitor/blob/main/_autodocs/errors.md This example shows how to correctly use secret files with Runitor, ensuring the specified file contains content. An error occurs if a file path provided with the 'file:' prefix is empty. ```bash # Ensure secret files contain content echo "myuuid" > /run/secrets/check-uuid runitor -uuid file:/run/secrets/check-uuid -- cmd ``` -------------------------------- ### Runitor Cron Expression Examples Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Use the -at flag with 5-field cron expressions to schedule tasks. Supported fields are minute, hour, day_of_month, month, and day_of_week. Special characters like '*', ',', '-', and '/' can be used for flexible scheduling. ```bash runitor -at "*/5 * * * *" -- cmd ``` ```bash runitor -at "0 2 * * *" -- cmd ``` ```bash runitor -at "0 9 * * 1" -- cmd ``` ```bash runitor -at "0 12 1,15 * *" -- cmd ``` ```bash runitor -at "0 6 */3 * *" -- cmd ``` -------------------------------- ### Set Command Execution Schedule with Cron Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Schedule command execution using cron expressions with the `-at` flag. This is mutually exclusive with the `-every` flag. Examples demonstrate daily and weekly scheduling. ```bash # Every day at 2 AM and 2 PM runitor -at "0 2,14 * * *" -uuid abc123 -- command # Every Monday at 9 AM runitor -at "0 9 * * 1" -uuid abc123 -- command ``` -------------------------------- ### Configure API Retries Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Specify the number of retries for transient API failures (408, 429, 5xx) using `-api-retries`. The default is 2. Retries use linear backoff starting at 1 second. ```bash runitor -api-retries 3 -uuid abc123 -- cmd ``` -------------------------------- ### Handle Cron Range Start Error Source: https://github.com/bdd/runitor/blob/main/_autodocs/errors.md Use errors.Is to check for ErrCronRangeStart when parsing cron expressions. This error is returned if the start of a range is not a valid integer. ```go sched, err := ParseCron("x-5 * * * *") if err != nil { // Error message: "parsing minutes: invalid range start \"x\": ..." log.Fatal(err) } ``` -------------------------------- ### Initialize API Client Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/apiclient.md Demonstrates how to initialize the APIClient with a base URL and an HTTP client with a timeout. This is a prerequisite for making any API calls. ```go client := &APIClient{ BaseURL: "https://hc-ping.com", Retries: 2, Client: &http.Client{Timeout: 5 * time.Second}, } ``` -------------------------------- ### RingBuffer Capacity (Cap) Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Get the maximum number of bytes the ring buffer can hold. ```go func (r *RingBuffer) Cap() int ``` -------------------------------- ### RingBuffer.Seek Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Adjusts the read/write position within the RingBuffer's data. Only seeking from the start of the buffer is supported. ```APIDOC ## RingBuffer.Seek ### Description Seeks to the specified offset from the start of the buffer's data. ### Method Signature ```go func (r *RingBuffer) Seek(offset int64, whence int) (int64, error) ``` ### Parameters #### Path Parameters - **offset** (int64) - Required - Offset in bytes - **whence** (int) - Required - Origin: only `io.SeekStart` supported ### Returns - **int64** - New offset from the start. - **error** - Error if the seek operation fails. ### Errors - `io.SeekStart` is the only supported `whence` value. - Negative offsets are rejected. - Offsets beyond the buffer length are clamped. ### Example ```go // Seek to start and read all data again buf.Seek(0, io.SeekStart) data := make([]byte, 1024) n, _ := buf.Read(data) ``` ``` -------------------------------- ### Create and Use RingBuffer Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Demonstrates creating a RingBuffer, writing data to it, and then reading data back. The buffer capacity is set during initialization. ```go buf := NewRingBuffer(10_000) // Write command output buf.Write([]byte("command output here")) // Read back when ready data := make([]byte, 256) n, err := buf.Read(data) ``` -------------------------------- ### RingBuffer Length (Len) Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Get the current number of bytes stored in the buffer. This excludes data that has been overwritten. ```go func (r *RingBuffer) Len() int ``` -------------------------------- ### Get Method Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Retrieves the contained value and a boolean indicating its presence. Useful for safely accessing the value. ```APIDOC ### Get Retrieves the value and a boolean indicating if it was defined. ```go func (o Optional[T]) Get() (T, bool) ``` **Returns:** The value and a boolean; boolean is `true` if value is defined, `false` if this is a `None()`. **Example:** ```go val, ok := opt.Get() if ok { fmt.Printf("Limit is %d bytes\n", val) } else { fmt.Println("No limit set") } ``` ``` -------------------------------- ### InstanceConfig with Optional PingBodyLimit Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Demonstrates using Optional for instance configuration, specifically for a PingBodyLimit that may or may not be provided by a server response. ```go type InstanceConfig struct { PingBodyLimit Optional[uint] } // Server response may or may not include the header icfg := &InstanceConfig{} icfg.FromResponse(resp) // Populates PingBodyLimit // Check if server set a limit if limit, ok := icfg.PingBodyLimit.Get(); ok { // Use server's limit } else { // Use default limit } ``` -------------------------------- ### RingBuffer Total Written (Written) Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Get the total number of bytes written to the buffer, including any data that has been overwritten. ```go func (r *RingBuffer) Written() int ``` -------------------------------- ### Build and Release a Rebuild Source: https://github.com/bdd/runitor/blob/main/MAINTAINER.md Use this command to build and prepare a release when an update to Go requires a new build. Ensure the Nix environment is set up and worktrees are managed correctly. ```bash nix develop --override-input nixpkgs github:NixOS/nixpkgs/nixpkgs-unstable RELEASE=vX.Y.Z RELBUILD=${RELEASE}-build.N WORKTREE=$(git rev-parse --show-toplevel)/build/worktree/${RELEASE} git worktree remove ${WORKTREE} git worktree add ${WORKTREE} ${RELEASE} GOTOOLCHAIN=go1.X.Y export WORKTREE GOTOOLCHAIN ./scripts/mkrel ${RELBUILD} # Cleanup git worktree remove $WORKTREE unset WORKTREE GOTOOLCHAIN ``` -------------------------------- ### Runitor Go Library Execution Source: https://github.com/bdd/runitor/blob/main/_autodocs/README.md Shows how to initialize the Runitor API client and execute a command with success and exit code reporting. Ensure the http.Client is configured with an appropriate timeout. ```go import "bdd.fi/x/runitor/internal" // Create client client := &APIClient{ BaseURL: "https://hc-ping.com", Retries: 2, Client: &http.Client{Timeout: 5 * time.Second}, } // Execute command and report cfg := RunConfig{ OnSuccess: PingTypeSuccess, OnNonzeroExit: PingTypeExitCode, } exitCode := Run( []string{"sh", "-c", "echo ok"}, cfg, "uuid-here", client, ) ``` -------------------------------- ### Build and Publish OCI Images Source: https://github.com/bdd/runitor/blob/main/MAINTAINER.md Execute these commands to build and publish OCI images after a release. This involves setting up the binfmt interpreter, configuring container authentication, and using the mkoci script. ```bash sudo podman run --privileged --rm tonistiigi/binfmt --install arm,arm64 mkdir -m 0700 -p ${XDG_RUNTIME_DIR}/containers pass show host/$(hostname -s)/containers/auth.json > ${XDG_RUNTIME_DIR}/containers/auth.json RELEASE=vX.Y.Z RELBUILD=${RELEASE}-build.N ./scripts/mkoci build ./scripts/mkoci tag_rt_shorts ./scripts/mkoci tag_default_rt ./scripts/mkoci push shred -u ${XDG_RUNTIME_DIR}/containers/auth.json ``` -------------------------------- ### Run Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Executes a command and sends pings to a monitoring service. It takes the command to execute, a configuration object, a handle for the monitoring service, and a Pinger implementation. ```APIDOC ## Run ### Description Executes command and sends pings to monitoring service. ### Method func ### Signature Run(cmd []string, cfg RunConfig, handle string, p Pinger) int ### Parameters - **cmd** ([]string) - Command with arguments - **cfg** (RunConfig) - Execution configuration - **handle** (string) - Check UUID or "key/slug" format - **p** (Pinger) - Pinger implementation (usually *APIClient) ### Returns - **int** - Command exit code (or 1 if execution failed) ``` -------------------------------- ### Capture Command Output with RingBuffer Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md This snippet demonstrates how to use RingBuffer to capture the standard output and standard error of a command. It shows how to initialize the buffer, direct command output to it, check for truncation, and read the buffered data. ```go // Create a 10KB buffer for command output buf := NewRingBuffer(10_000) // Execute command with output directed to buffer cmd := exec.Command("long-running-process") cmd.Stdout = buf cmd.Stderr = buf cmd.Run() // Check if output was truncated if buf.Wrapped() { fmt.Printf("Output truncated; retained last %d of %d bytes\n", buf.Cap(), buf.Written()) } // Seek and read all buffered data buf.Seek(0, io.SeekStart) body := make([]byte, buf.Len()) buf.Read(body) // Send to healthchecks.io client.PingSuccess(handle, params, bytes.NewReader(body)) ``` -------------------------------- ### Handle Cron Range Order Error Source: https://github.com/bdd/runitor/blob/main/_autodocs/errors.md Use errors.Is to check for ErrCronRangeOrder when parsing cron expressions. This error is returned if the start value of a range is greater than the end value. ```go sched, err := ParseCron("5-1 * * * *") if err != nil { // Error message: "parsing minutes: range start > end" log.Fatal(err) } ``` -------------------------------- ### Create HTTP client with custom transport Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Demonstrates creating a Go http.Client with a custom transport, NewDefaultTransportWithResumption, and setting a specific timeout. This allows for more control over request handling. ```go transport := NewDefaultTransportWithResumption() client := &http.Client{ Transport: transport, Timeout: 5 * time.Second, } ``` -------------------------------- ### General Backup with Runitor (No Output) Source: https://github.com/bdd/runitor/blob/main/README.md Perform backups without attaching command output to the ping. This is useful as backup software might leak sensitive information like filenames and paths. ```bash # Do not attach output to ping. # Backup software may leak filenames and paths. runitor -no-output-in-ping -- restic backup /home /etc ``` -------------------------------- ### Go Main Package Import Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Illustrates the import path for the main Runitor package. Library use is not supported; cmd/runitor is the intended entry point. ```go import "bdd.fi/x/runitor/cmd/runitor" ``` -------------------------------- ### None Constructor Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Creates an empty Optional, representing the absence of a value. Use this when no value is present. ```go func None[T any]() Optional[T] ``` ```go opt := None[uint]() ``` -------------------------------- ### FromFlagOrEnv Function Signature Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Resolves a configuration value by checking a flag first, then a list of environment variables. Supports reading values from files prefixed with 'file:'. ```go func FromFlagOrEnv(flg string, envvars []string) string ``` -------------------------------- ### Set Command Execution Interval Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Use the `-every` flag to repeatedly run a command at a specified interval. This is mutually exclusive with the `-at` flag. Examples show intervals in hours and combined hours/minutes. ```bash # Run every 6 hours runitor -every 6h -uuid abc123 -- command # Run every 2 hours and 24 minutes runitor -every 2h24m -uuid abc123 -- command ``` -------------------------------- ### Some Constructor Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Wraps a given value into an Optional type, marking it as defined. Use this when a value is present. ```go func Some[T any](val T) Optional[T] ``` ```go opt := Some(uint(10000)) ``` -------------------------------- ### Configure RunConfig for Direct Go Execution Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Use this configuration when calling the Run() function directly in Go. It allows fine-grained control over ping behavior, output capture, and execution handling. ```go cfg := RunConfig{ Quiet: false, Silent: false, NoStartPing: false, NoOutputInPing: false, NoRunId: false, Create: false, PingBodyLimitIsExplicit: true, PingBodyLimit: 10000, OnSuccess: PingTypeSuccess, OnNonzeroExit: PingTypeExitCode, OnExecFail: PingTypeFail, } exitCode := Run(cmd, cfg, handle, client) ``` -------------------------------- ### Run Function Signature Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Executes a command with specified configuration and sends pings to a monitoring API. Returns the command's exit code or 1 if execution fails. ```go func Run(cmd []string, cfg RunConfig, handle string, p Pinger) int ``` -------------------------------- ### APIClient Methods Source: https://github.com/bdd/runitor/blob/main/_autodocs/INDEX.md The APIClient type facilitates communication with Healthchecks.io. It provides methods to signal the start, success, or failure of a task, log information, send exit codes, and perform HTTP requests with retry logic. ```APIDOC ## APIClient Methods ### Description Methods for interacting with the Healthchecks.io API to report task status and send data. ### Methods - `PingStart()`: Sends a signal indicating the start of a task. - `PingSuccess()`: Signals that a task has completed successfully. - `PingFail()`: Indicates that a task has failed. - `PingLog()`: Sends a log message without changing the task status. - `PingExitCode(code int)`: Sends the numeric exit code of a task. - `Post(url string, params PingParams)`: Performs an HTTP POST request with built-in retry logic. - `NewDefaultTransportWithResumption()`: Creates a transport with TLS session caching for resumable connections. ``` -------------------------------- ### RunConfig Struct Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Configuration options for running a command, including silent operation, ping behavior, and notification types for different outcomes. ```go type RunConfig struct { Quiet bool Silent bool NoStartPing bool NoOutputInPing bool NoRunId bool Create bool PingBodyLimitIsExplicit bool PingBodyLimit uint OnSuccess PingType OnNonzeroExit PingType OnExecFail PingType } ``` -------------------------------- ### InstanceConfig Methods Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md The InstanceConfig type holds server configuration derived from ping response headers, including the PingBodyLimit. ```APIDOC ## InstanceConfig Methods ### Description Represents server configuration extracted from ping response headers. ### Methods - **FromResponse(resp *http.Response)**: Creates an InstanceConfig from an HTTP response. ``` -------------------------------- ### None Constructor Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Creates an empty Optional representing no value. Use this when a value is explicitly absent. ```APIDOC ### None Creates an empty `Optional` representing no value. ```go func None[T any]() Optional[T] ``` **Returns:** `Optional[T]` with defined=false and zero value of T. **Example:** ```go opt := None[uint]() ``` ``` -------------------------------- ### Set Version String at Build Time Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Embeds a version string into the binary during the build process. This version can be retrieved at runtime. ```bash go build -ldflags "-X main.Version=v1.2.3" ./cmd/runitor ``` -------------------------------- ### APIClient Methods Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md The APIClient provides methods for interacting with the Healthchecks.io API. It supports starting pings, logging ping events, marking pings as successful or failed, and handling exit codes. It also includes a generic Post method for direct HTTP requests. ```APIDOC ## APIClient Methods ### Description Provides methods for interacting with the Healthchecks.io API, including starting and managing ping events, and making generic HTTP requests. ### Methods - **PingStart(handle string, params PingParams) (*InstanceConfig, error)**: Initiates a ping event. - **PingSuccess(handle string, params PingParams, body io.ReadSeeker) (*InstanceConfig, error)**: Marks a ping event as successful. - **PingFail(handle string, params PingParams, body io.ReadSeeker) (*InstanceConfig, error)**: Marks a ping event as failed. - **PingLog(handle string, params PingParams, body io.ReadSeeker) (*InstanceConfig, error)**: Logs details for a ping event. - **PingExitCode(handle string, params PingParams, exitCode int, body io.ReadSeeker) (*InstanceConfig, error)**: Marks a ping event with a specific exit code. - **Post(url, contentType string, body io.ReadSeeker) (*http.Response, error)**: Performs a generic HTTP POST request. ``` -------------------------------- ### FromFlagOrEnv Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Resolves a configuration value from a command-line flag or environment variables, with support for file indirection. It checks flags first, then environment variables in the specified order. ```APIDOC ## FromFlagOrEnv ### Description Resolves configuration value from flag or environment variable with file indirection support. ### Method func ### Signature FromFlagOrEnv(flg string, envvars []string) string ### Parameters - **flg** (string) - Flag value (takes precedence if non-empty) - **envvars** ([]string) - Environment variable names to check in order ### Returns - **string** - Resolved value (empty string if none found) ### File Indirection Prefix with `file:` to read from file path (e.g., `file:/run/secrets/uuid`) ``` -------------------------------- ### Optional Value Handling in Go Source: https://github.com/bdd/runitor/blob/main/_autodocs/README.md Demonstrates the use of Optional[T] to distinguish between unset values and zero values in Go. Used for InstanceConfig.PingBodyLimit. ```go opt := Some(10000) // Defined val, ok := opt.Get() // Returns (10000, true) opt := None[uint]() // Undefined val, ok := opt.Get() // Returns (0, false) ``` -------------------------------- ### Print Version Information Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md The `-version` flag prints the current version of Runitor and then exits. ```bash runitor -version ``` -------------------------------- ### NewRingBuffer Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Allocates and initializes a new RingBuffer with a specified capacity. This is the entry point for creating a RingBuffer instance. ```APIDOC ## NewRingBuffer ### Description Allocates a new `RingBuffer` with the specified capacity. ### Method Signature ```go func NewRingBuffer(cap int) *RingBuffer ``` ### Parameters #### Path Parameters - **cap** (int) - Required - Capacity in bytes ### Returns - ** exttt{*}RingBuffer** - Pointer to initialized `RingBuffer`. ### Example ```go // Create a 10KB buffer buf := NewRingBuffer(10_000) // Write command output buf.Write([]byte("command output here")) // Read back when ready data := make([]byte, 256) n, err := buf.Read(data) ``` ``` -------------------------------- ### InstanceConfig Structure Source: https://github.com/bdd/runitor/blob/main/_autodocs/types.md Represents server-provided configuration for an instance, primarily used for limiting ping body size. It reads configuration from HTTP response headers. ```go type InstanceConfig struct { PingBodyLimit Optional[uint] } ``` -------------------------------- ### Some Constructor Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md Wraps a value as a defined Optional. Use this constructor when you have a value to store. ```APIDOC ## Constructors ### Some Wraps a value as a defined `Optional`. ```go func Some[T any](val T) Optional[T] ``` | Parameter | Type | Description | |-----------|------|-------------| | val | T | Value to wrap | **Returns:** `Optional[T]` with defined=true and value=val. **Example:** ```go opt := Some(uint(10000)) ``` ``` -------------------------------- ### RingBuffer Initialization in Go Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Initialize a RingBuffer to capture output when PingBodyLimit is greater than 0. This buffer automatically discards the oldest data when its capacity is exceeded, ensuring only the last N bytes of output are kept. ```go buffer := NewRingBuffer(int(cfg.PingBodyLimit)) ``` -------------------------------- ### Runitor Configuration Precedence: Flag vs. Environment Source: https://github.com/bdd/runitor/blob/main/_autodocs/README.md Illustrates how Runitor prioritizes configuration values, with command-line flags taking precedence over environment variables. If both are set, the flag value is used. ```bash # Using flag runitor -uuid abc123 -- cmd ``` ```bash # Using environment export CHECK_UUID=abc123 runitor -- cmd ``` ```bash # Environment takes effect only if flag not passed # If both set, flag wins runitor -uuid from-flag -- cmd # Uses from-flag, ignores $CHECK_UUID ``` -------------------------------- ### Handle -create Flag Validation Error Source: https://github.com/bdd/runitor/blob/main/_autodocs/errors.md Shows the correct usage of the -create flag in Runitor, which requires a slug and ping key. Using -create with a UUID results in an error. ```bash # Wrong: -create with UUID runitor -create -uuid abc123 -- cmd # Error! # Right: -create with slug/key runitor -create -slug new-check -ping-key mykey -- cmd ``` -------------------------------- ### Schedule Database Backup Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Schedules a database backup script to run twice daily at 2 AM and 2 PM using cron syntax. A ping-key is required. ```bash # Run backup at 2 AM and 2 PM daily runitor -slug db-backup \ -at "0 2,14 * * *" \ -ping-key file:/run/secrets/ping-key \ -- /script/db-backup ``` -------------------------------- ### Go Internal Package Import Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Shows how to import the internal Runitor package. The dot import is specifically used by cmd/runitor. ```go import . "bdd.fi/x/runitor/internal" // Dot import (used by cmd/runitor) ``` ```go import "bdd.fi/x/runitor/internal" client := &internal.APIClient{...} ``` -------------------------------- ### Read from environment variable pointing to file Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Shows how to set an environment variable with a 'file:' prefix to specify the path for CHECK_UUID. Runitor will then read the UUID from the specified file. ```bash # Read from environment variable pointing to file export CHECK_UUID=file:/run/secrets/check-uuid runitor -- cmd ``` -------------------------------- ### Runitor File Indirection for Secrets: UUID from File Source: https://github.com/bdd/runitor/blob/main/_autodocs/README.md Shows how to use the `file:` prefix to read configuration values, such as UUID, from a file. This is useful for managing secrets in containerized environments. ```bash # Read UUID from file runitor -uuid file:/run/secrets/check-uuid -- cmd ``` ```bash # Via environment export CHECK_UUID=file:/run/secrets/check-uuid runitor -- cmd ``` -------------------------------- ### Unwrap with Default Pattern Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/optional.md A common pattern to safely retrieve a value from an Optional, providing a default if the Optional is not defined. ```go limit, ok := opt.Get() if !ok { limit = 10000 // default } ``` -------------------------------- ### Seek in RingBuffer Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Seeks to a specified offset within the RingBuffer's data. Only `io.SeekStart` is supported as the whence parameter. Negative offsets are rejected, and offsets beyond the buffer length are clamped. ```go // Seek to start and read all data again buf.Seek(0, io.SeekStart) data := make([]byte, 1024) n, _ := buf.Read(data) ``` -------------------------------- ### Define RunConfig Struct Source: https://github.com/bdd/runitor/blob/main/_autodocs/types.md Defines the RunConfig struct which holds configuration options for controlling command execution behavior, including output capturing and ping settings. Adjust these fields to customize how commands are run and monitored. ```go type RunConfig struct { Quiet bool // No cmd stdout Silent bool // No cmd stdout or stderr NoStartPing bool // Don't send Start ping NoOutputInPing bool // Don't send command std{out, err} with Success and Failure pings NoRunId bool // Don't generate and send a run id per run in pings Create bool // Create a new check if slug is not found in the project PingBodyLimitIsExplicit bool // Explicit limit via flags PingBodyLimit uint // Truncate ping body to last N bytes OnSuccess PingType // Ping type to send when command exits successfully OnNonzeroExit PingType // Ping type to send when command exits with a nonzero code OnExecFail PingType // Ping type to send when runitor cannot execute the command } ``` -------------------------------- ### Create Missing Monitoring Check Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Creates a new monitoring check with a specified slug and ping key if it does not already exist in the project. Executes a given script upon creation. ```bash # Create a new check in the project if it doesn't exist runitor -create \ -slug new-monitor \ -ping-key myprojectkey \ -- /script/new-task ``` -------------------------------- ### Run Function Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Executes a command and sends appropriate pings to the monitoring API based on the execution result and configuration. It handles success, non-zero exit codes, and execution failures by sending different types of pings. ```APIDOC ## Run Executes a command and sends appropriate pings to the monitoring API. ### Function Signature ```go func Run(cmd []string, cfg RunConfig, handle string, p Pinger) int ``` ### Parameters - **cmd** ([]string) - Required - Command and arguments (cmd[0] is executable path) - **cfg** (RunConfig) - Required - Execution configuration - **handle** (string) - Required - Check UUID or formatted key/slug handle - **p** (Pinger) - Required - API client (typically `*APIClient`) ### Returns - **int** - Exit code from the command, or 1 if execution failed. ### Ping Sequence 1. Sends start ping (unless `-no-start-ping`) 2. Executes command, capturing output to ping body buffer 3. On success (exit code 0): sends success ping 4. On non-zero exit: sends failure or exit-code ping 5. On execution failure: sends fail or exit-code ping ### Output Handling - Sends command output in ping body unless `-no-output-in-ping` - Respects ping body limit, truncating older output - Respects server-provided `Ping-Body-Limit` header ### Example ```go cfg := RunConfig{ OnSuccess: PingTypeSuccess, OnNonzeroExit: PingTypeExitCode, OnExecFail: PingTypeFail, } client := &APIClient{ BaseURL: "https://hc-ping.com", Retries: 2, Client: &http.Client{Timeout: 5 * time.Second}, } exitCode := Run([]string{"bash", "-c", "echo ok"}, cfg, "uuid-123", client) os.Exit(exitCode) ``` ``` -------------------------------- ### Go Error Handling Patterns Source: https://github.com/bdd/runitor/blob/main/_autodocs/errors.md This snippet shows how to check for specific errors using `errors.Is`, check for wrapped errors, and inspect error messages using `strings.Contains`. It also includes a fallback for generic error handling. ```Go import "errors" import "strings" import "log" // Assume these errors are defined elsewhere var ErrNonRetriable = errors.New("non-retriable error") var ErrMaxTries = errors.New("max retries exhausted") func processError(err error) { // Check for specific errors if errors.Is(err, ErrNonRetriable) { // Non-retriable API error log.Println("Handling non-retriable error") } // Check for wrapped errors if errors.Is(err, ErrMaxTries) { // All retries exhausted log.Println("Handling max retries error") } // Check if error contains message if strings.Contains(err.Error(), "expected 5 fields") { // Cron parse error log.Println("Handling cron parse error") } // Generic error handling if err != nil { log.Fatal(err) } } ``` -------------------------------- ### Handle Type Patterns Source: https://github.com/bdd/runitor/blob/main/_autodocs/README.md Illustrates the two patterns for check identification: direct UUID and a combination of key and slug. UUID takes precedence. ```text UUIDHandle → Direct UUID: 8116e449-d71c-4112-8f5d-a66f60902091 KeyAndSlugHandle → Key/slug combo: ping-key/check-slug ``` -------------------------------- ### Default Configuration Values Source: https://github.com/bdd/runitor/blob/main/_autodocs/configuration.md Defines default values for the base URL, timeout, and retries within the application code. These can be overridden by flags or environment variables. ```go const DefaultBaseURL = "https://hc-ping.com" const DefaultTimeout = 5 * time.Second const DefaultRetries = 2 ``` -------------------------------- ### Execution Configuration Flags Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Flags for defining when the command should be executed, using intervals or cron expressions. ```APIDOC ## Execution Configuration Flags ### `-every ` Run the command repeatedly at the specified interval (mutually exclusive with `-at`). **Example:** ```bash # Run every 6 hours runitor -every 6h -uuid abc123 -- command # Run every 2 hours and 24 minutes runitor -every 2h24m -uuid abc123 -- command ``` ### `-at ` Run the command at times matching the cron expression (mutually exclusive with `-every`). See `ParseCron` for expression syntax. **Example:** ```bash # Every day at 2 AM and 2 PM runitor -at "0 2,14 * * *" -uuid abc123 -- command # Every Monday at 9 AM runitor -at "0 9 * * 1" -uuid abc123 -- command ``` ``` -------------------------------- ### io.Seeker Interface Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/ringbuffer.md Implements the io.Seeker interface for seeking within the buffer. ```APIDOC ## io.Seeker ### Description Implements the `io.Seeker` interface, allowing the read/write position within the `RingBuffer` to be changed. ### Method Signature `Seek(offset int64, whence int) (int64, error)` ``` -------------------------------- ### Exec Source: https://github.com/bdd/runitor/blob/main/_autodocs/API-SUMMARY.md Executes a command and captures its standard output and standard error. It returns the exit code and any error encountered during execution. ```APIDOC ## Exec ### Description Executes command and captures output. ### Method func ### Signature Exec(cmd []string, stdout, stderr io.Writer) (exitCode int, err error) ### Parameters - **cmd** ([]string) - Command with arguments - **stdout** (io.Writer) - Output writer (nil to discard) - **stderr** (io.Writer) - Error writer (nil to discard) ### Returns - **int** - Exit code - **error** - nil on success ``` -------------------------------- ### Configure Ping on Non-Zero Exit Source: https://github.com/bdd/runitor/blob/main/_autodocs/api-reference/runitor.md Specify the ping type sent when a command exits with a non-zero code using `-on-nonzero-exit`. Options are `exit-code`, `success`, `fail`, and `log`. The default is `exit-code`. ```bash # Explicitly fail on non-zero exit runitor -on-nonzero-exit fail -uuid abc123 -- cmd ``` -------------------------------- ### Runitor Core Functions Source: https://github.com/bdd/runitor/blob/main/_autodocs/INDEX.md The runitor command-line interface and core functions enable command execution with monitoring. Key functions include executing commands, resolving configuration from flags or environment variables, and managing different execution modes. ```APIDOC ## Runitor Core Functions ### Description Core functions for executing commands with monitoring, configuration management, and various operating modes. ### Methods - `Run()`: Executes a command with integrated monitoring capabilities. - `Exec()`: Provides low-level command execution functionality. - `FromFlagOrEnv(flagName string, envName string, defaultValue string)`: Resolves configuration values from command-line flags or environment variables. ### Operating Modes - **One-shot:** Executes a command once. - **Periodic:** Executes a command at regular intervals. - **Scheduled:** Executes a command based on a cron schedule. ```