=============== LIBRARY RULES =============== From library maintainers: - The module path is github.com/tecnickcom/nurago. The former github.com/tecnickcom/gogen path is deprecated and must not be used in new imports. - Import individual packages under pkg/, not the module root. Each package pulls only the dependencies it reaches, and 40 of the 70 reach no external module at all. - Packages that take configuration use variadic functional options: a New constructor with an opts ...Option parameter and WithXxx option functions. - The module is at v1 and every exported symbol under pkg/ is stable within v1. A high patch number reflects frequent additive releases, not API churn. - Guides and per-package pages are published at https://nurago.org, with a machine-readable index at https://nurago.org/llms.txt. ### Install Nurago via go get Source: https://github.com/tecnickcom/nurago/blob/main/README.md Use the standard Go toolchain to fetch the library. ```bash go get github.com/tecnickcom/nurago ``` -------------------------------- ### Initialize and use jirasrv Client Source: https://github.com/tecnickcom/nurago/blob/main/pkg/jirasrv/README.md This example demonstrates creating a new Jira client, configuring a request with query parameters, and executing it using SendRequest. It includes a mock server setup to illustrate how the client handles authentication and base path application. ```go // A stand-in for a Jira Server instance. Real code passes the Jira base // address and a personal access token. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println(r.Method, r.URL.Path, r.URL.RawQuery) fmt.Println("auth:", r.Header.Get("Authorization")) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"key":"PROJ-42","fields":{"summary":"login fails"}}`)) })) defer srv.Close() client, err := jirasrv.New(srv.URL, "personal-access-token") if err != nil { fmt.Println(err) return } query := url.Values{} query.Set("fields", "summary") // SendRequest covers any Jira REST endpoint, so the package does not // have to model the whole API surface. resp, err := client.SendRequest( context.TODO(), http.MethodGet, "/issue/PROJ-42", &query, nil, ) if err != nil { fmt.Println(err) return } // The base path (/rest/api/2) is applied by the client, so endpoints are // given relative to it. The caller owns the response body. defer func() { _ = resp.Body.Close() }() body, _ := io.ReadAll(resp.Body) var issue struct { Key string `json:"key"` Fields struct { Summary string `json:"summary"` } `json:"fields"` } err = json.Unmarshal(body, &issue) fmt.Println(issue.Key, issue.Fields.Summary, err) // Output: // GET /rest/api/2/issue/PROJ-42 fields=summary // auth: Bearer personal-access-token // PROJ-42 login fails ``` -------------------------------- ### Initialize and Start an HTTP Server Source: https://github.com/tecnickcom/nurago/blob/main/pkg/httpserver/README.md Demonstrates how to create a new server instance with custom options, start it in the background, and perform a graceful shutdown. ```go ctx := context.Background() srv, err := httpserver.New( ctx, &exampleBinder{}, httpserver.WithServerAddr(":0"), // ephemeral port; see srv.Addr() for the actual address httpserver.WithEnableDefaultRoutes(httpserver.PingRoute, httpserver.StatusRoute), httpserver.WithRequestTimeout(30*time.Second), httpserver.WithShutdownTimeout(5*time.Second), httpserver.WithLogger(slog.New(slog.DiscardHandler)), ) if err != nil { fmt.Println(err) return } // The server runs in the background; canceling ctx or calling Shutdown // stops it gracefully. srv.StartServer() // ... serve traffic ... err = srv.Shutdown(ctx) if err != nil { fmt.Println(err) return } fmt.Println("server stopped") // Output: // server stopped ``` -------------------------------- ### Full Paging Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/paging/README.md A complete example demonstrating the calculation of paging parameters and printing the result. ```go var ( currentPage uint = 3 pageSize uint = 5 totalItems uint = 17 ) // calculate new paging parameters p := paging.New(currentPage, pageSize, totalItems) fmt.Println(p) // Output: // {3 5 17 4 2 4 10 true true} ``` -------------------------------- ### Bootstrap Lifecycle Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/bootstrap/README.md A complete example showing how to use Bootstrap to manage application components and handle graceful shutdown, including the expected output. ```go // A real service lets Bootstrap block on SIGINT or SIGTERM. The example // cancels the context from inside the bind function so it terminates. ctx, cancel := context.WithCancel(context.TODO()) defer cancel() var wg sync.WaitGroup shutdown := make(chan struct{}) // BindFunc is where the application registers its own components: HTTP // servers, database connections, background workers. It receives the // application context, logger, and metrics client already wired. bindFn := func(ctx context.Context, _ *slog.Logger, mtr metrics.Client) error { worker(ctx, &wg, shutdown) mtr.IncErrorCounter("startup", "bind", "0") fmt.Println("application wired") // Stand-in for the signal that would normally end the process. cancel() return nil } // Bootstrap returns once every registered dependant has finished, or // with an error wrapping ErrShutdownTimeout if they exceed the budget. err := bootstrap.Bootstrap( bindFn, bootstrap.WithContext(ctx), bootstrap.WithShutdownSignalChan(shutdown), bootstrap.WithShutdownWaitGroup(&wg), bootstrap.WithShutdownTimeout(5*time.Second), bootstrap.WithCreateMetricsClientFunc(func() (metrics.Client, error) { return &metrics.Default{}, nil }), ) fmt.Println("bootstrap returned:", err) // Output: // application wired // worker stopped // bootstrap returned: ``` -------------------------------- ### Slack Client Integration Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/slack/README.md A complete example showing how to mock a Slack webhook endpoint, initialize the client, and send a message with default metadata. ```go // A stand-in for a Slack Incoming Webhook endpoint. Real code passes the // https://hooks.slack.com/services/... address issued by Slack. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, _ := io.ReadAll(r.Body) fmt.Println(string(body)) _, _ = w.Write([]byte("ok")) })) defer srv.Close() // The constructor takes the defaults applied to every message: sender // name, icon emoji, icon URL, and channel. client, err := slack.New(srv.URL, "deploybot", ":rocket:", "", "#releases") if err != nil { fmt.Println(err) return } // Empty metadata arguments fall back to the client defaults. err = client.Send(context.TODO(), "release v1.2.3 is live", "", "", "", "") fmt.Println("err:", err) // Output: // {"text":"release v1.2.3 is live","username":"deploybot","icon_emoji":":rocket:","channel":"#releases"} // err: ``` -------------------------------- ### Configure and execute a retriable HTTP request Source: https://github.com/tecnickcom/nurago/blob/main/pkg/httpretrier/README.md This example demonstrates setting up a retrier with a custom policy and executing a GET request against a test server that fails twice before succeeding. ```go // A server that fails twice before succeeding. attempts := 0 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { attempts++ if attempts < 3 { w.WriteHeader(http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusOK) })) defer srv.Close() retrier, err := httpretrier.New( srv.Client(), httpretrier.WithAttempts(4), httpretrier.WithDelay(time.Millisecond), httpretrier.WithJitter(time.Microsecond), // kept tiny so the example runs quickly httpretrier.WithRetryIfFn(httpretrier.RetryIfForReadRequests), ) if err != nil { fmt.Println(err) return } req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, srv.URL, nil) if err != nil { fmt.Println(err) return } resp, err := retrier.Do(req) if err != nil { fmt.Println(err) return } defer func() { _ = resp.Body.Close() }() fmt.Println(resp.StatusCode, "after", attempts, "attempts") // Output: // 200 after 3 attempts ``` -------------------------------- ### Construct and Start a Periodic Scheduler Source: https://github.com/tecnickcom/nurago/blob/main/pkg/periodic/README.md Demonstrates how to initialize a Periodic scheduler using periodic.New and manage its lifecycle with Start and Stop. ```go p, err := periodic.New( 30*time.Second, // run every 30 s 5*time.Second, // add up to 5 s of random jitter 10*time.Second, // each call gets a 10 s deadline myTask, ) if err != nil { log.Fatal(err) } p.Start(ctx) defer p.Stop() ``` -------------------------------- ### Example usage of IsPwnedPassword Source: https://github.com/tecnickcom/nurago/blob/main/pkg/passwordpwned/README.md A complete example demonstrating client initialization with a custom URL and checking multiple passwords. ```go srv := rangeServer() defer srv.Close() // Real code omits WithURL and uses the default HIBP endpoint. client, err := passwordpwned.New(passwordpwned.WithURL(srv.URL)) if err != nil { fmt.Println(err) return } pwned, err := client.IsPwnedPassword(context.TODO(), "password") fmt.Println("password:", pwned, err) pwned, err = client.IsPwnedPassword(context.TODO(), "correct horse battery staple") fmt.Println("passphrase:", pwned, err) // Output: // password: true // passphrase: false ``` -------------------------------- ### Example usage with sqlmock Source: https://github.com/tecnickcom/nurago/blob/main/pkg/sqlxtransaction/README.md A self-contained example demonstrating transaction execution and commit verification using sqlmock. ```go // A real program would use a *sqlx.DB from sqlx.Connect. The mock keeps // the example self-contained and its output deterministic. mockDB, mock, err := sqlmock.New() if err != nil { fmt.Println(err) return } db := sqlx.NewDb(mockDB, "sqlmock") defer func() { _ = db.Close() }() mock.ExpectBegin() mock.ExpectExec("INSERT INTO audit").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // The transaction is committed when run returns nil, and rolled back // when it returns an error or panics. err = sqlxtransaction.Exec( context.TODO(), db, func(ctx context.Context, tx *sqlx.Tx) error { _, err := tx.ExecContext(ctx, "INSERT INTO audit (event) VALUES ('login')") if err != nil { return fmt.Errorf("writing audit row: %w", err) } return nil }, ) fmt.Println("committed:", err) // Output: // committed: ``` -------------------------------- ### Clone and Initialize Project Source: https://github.com/tecnickcom/nurago/blob/main/examples/service/README.md Commands to clone the repository, enter the directory, and install dependencies for local development. ```bash git clone https://github.com/nuragoexampleowner/nuragoexample.git cd nuragoexample DEVMODE=LOCAL make x ``` -------------------------------- ### Example of Chunk usage Source: https://github.com/tecnickcom/nurago/blob/main/pkg/strsplit/README.md A complete example showing how to split a string into chunks of a specific size with a limit on the number of chunks returned. ```go str := "helloworld\nbellaciao" d := strsplit.Chunk(str, 5, 3) fmt.Println(d) // Output: // [hello world bella] ``` -------------------------------- ### Example usage of PProfHandler Source: https://github.com/tecnickcom/nurago/blob/main/pkg/profiling/README.md Demonstrates setting up a router with PProfHandler and making a request to a pprof endpoint. ```go router := httprouter.New() // One wildcard route serves every pprof endpoint. The mount prefix is // arbitrary, as the handler reads the endpoint from the wildcard // parameter rather than from the request path. router.HandlerFunc( http.MethodGet, "/pprof/*"+profiling.WildcardParamName, profiling.PProfHandler, ) srv := httptest.NewServer(router) defer srv.Close() // The goroutine profile is a named runtime profile forwarded to // pprof.Handler, so it needs no explicit registration. req, err := http.NewRequestWithContext( context.TODO(), http.MethodGet, srv.URL+"/pprof/goroutine?debug=1", nil, ) if err != nil { fmt.Println(err) return } resp, err := srv.Client().Do(req) if err != nil { fmt.Println(err) return } defer func() { _ = resp.Body.Close() }() fmt.Println(resp.StatusCode) // Output: // 200 ``` -------------------------------- ### Kafka Producer and Consumer Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/kafka/README.md Demonstrates initializing a producer and consumer, sending a raw payload, and receiving it using the kafka package. ```go queue := &exampleQueue{} producer, err := kafka.NewProducer( []string{"127.0.0.1:9092"}, "events", kafka.WithKafkaWriter(queue), ) if err != nil { fmt.Println(err) return } defer func() { _ = producer.Close() }() ctx := context.TODO() err = producer.Send(ctx, []byte("raw payload")) if err != nil { fmt.Println(err) return } consumer, err := kafka.NewConsumer( []string{"127.0.0.1:9092"}, "events", "example-group", kafka.WithKafkaReader(queue), ) if err != nil { fmt.Println(err) return } defer func() { _ = consumer.Close() }() msg, err := consumer.Receive(ctx) fmt.Println(string(msg), err) // Output: // raw payload ``` -------------------------------- ### Example of configuring awsopt.Options Source: https://github.com/tecnickcom/nurago/blob/main/pkg/awsopt/README.md Shows the full workflow of creating an Options instance, adding a region and custom credentials, and loading the configuration. ```go // The zero value is ready to use. var opts awsopt.Options opts.WithRegion("eu-west-1") // Any config.LoadOptionsFunc from the SDK can be appended, so nothing in // the SDK is out of reach. Static credentials keep the example offline; // real code relies on the default credential chain. opts.WithAWSOption(config.WithCredentialsProvider( credentials.NewStaticCredentialsProvider("AKID", "SECRET", ""), )) awsCfg, err := opts.LoadDefaultConfig(context.TODO()) if err != nil { fmt.Println(err) return } // awsCfg is passed directly to any aws-sdk-go-v2 service constructor, // for example s3.NewFromConfig or secretsmanager.NewFromConfig. fmt.Println(awsCfg.Region) // Output: // eu-west-1 ``` -------------------------------- ### Usage of awsopt.Options Source: https://github.com/tecnickcom/nurago/blob/main/pkg/awsopt/README.md Demonstrates how to initialize options, set a region from a URL, and load the default configuration. ```go var opts awsopt.Options opts.WithRegionFromURL("https://s3.eu-west-1.amazonaws.com", "") awsCfg, err := opts.LoadDefaultConfig(ctx) if err != nil { return err } // awsCfg is ready for any aws-sdk-go-v2 service client: // s3.NewFromConfig(awsCfg), secretsmanager.NewFromConfig(awsCfg), … ``` -------------------------------- ### IsNil Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/typeutil/README.md Example showing the use of IsNil to detect a nil channel. ```go var nilChan chan int v := typeutil.IsNil(nilChan) fmt.Println(v) // Output: // true ``` -------------------------------- ### Initialize and use Valkey client Source: https://github.com/tecnickcom/nurago/blob/main/pkg/valkey/README.md Demonstrates how to initialize a client with server options and channels, then perform typed data operations. ```go srvOpts := valkey.SrvOptions{InitAddress: []string{"localhost:6379"}} client, err := valkey.New( ctx, srvOpts, valkey.WithChannels("events", "notifications"), ) if err != nil { return err } defer client.Close() // Store and retrieve a typed value: type Payload struct{ Message string } if err := client.SetData(ctx, "my-key", Payload{"hello"}, time.Hour); err != nil { return err } var p Payload if err := client.GetData(ctx, "my-key", &p); err != nil { return err } // Publish and consume a typed message: if err := client.SendData(ctx, "events", Payload{"fired"}); err != nil { return err } var event Payload channel, err := client.ReceiveData(ctx, &event) ``` -------------------------------- ### Filter Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/sliceutil/README.md Example showing how to filter a slice of strings based on a predicate function. ```go s := []string{"Hello", "World", "Extra"} filterFn := func(_ int, v string) bool { return v == "World" } s2 := sliceutil.Filter(s, filterFn) fmt.Println(s2) // Output: // [World] ``` -------------------------------- ### Loading Configuration with Defaults and Overrides Source: https://github.com/tecnickcom/nurago/blob/main/pkg/config/README.md Demonstrates setting up a temporary configuration file, applying environment variable overrides, and loading the final configuration into a struct. ```go // A real service ships config.json alongside the binary, or relies on // the search path: ./, $HOME/./, /etc//. dir, err := os.MkdirTemp("", "nurago-config-example") if err != nil { fmt.Println(err) return } defer func() { _ = os.RemoveAll(dir) }() file := `{"server_address":":9090","max_workers":8}` err = os.WriteFile(filepath.Join(dir, "config.json"), []byte(file), 0o600) if err != nil { fmt.Println(err) return } // Environment variables override the file, which overrides the // defaults. The prefix keeps the service's variables namespaced. _ = os.Setenv("EXAMPLESRV_MAX_WORKERS", "16") defer func() { _ = os.Unsetenv("EXAMPLESRV_MAX_WORKERS") }() cfg := &appConfig{} err = config.Load("examplesrv", dir, "EXAMPLESRV", cfg) if err != nil { fmt.Println(err) return } fmt.Println(cfg.ServerAddress, cfg.MaxWorkers, cfg.Log.Level) // Output: // :9090 16 info ``` -------------------------------- ### Deterministic backoff example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/backoff/README.md A deterministic example showing the progression of delays with jitter disabled. ```go s := backoff.New(backoff.Config{ Base: 100 * time.Millisecond, Factor: 2, Jitter: 0, // disabled so the example output is deterministic MaxDelay: 350 * time.Millisecond, }) for range 4 { fmt.Println(s.Next()) } // Output: // 100ms // 200ms // 350ms // 350ms ``` -------------------------------- ### Initialize logutil Config and Logger Source: https://github.com/tecnickcom/nurago/blob/main/pkg/logutil/README.md Demonstrates creating a configuration with string-based options and initializing a slog logger. The example shows how to set the format, level, and common attributes before retrieving the logger instance. ```go // Configuration usually comes from environment variables or a config // file, so the string-based options accept the raw values directly. cfg, err := logutil.NewConfig( logutil.WithFormatStr("json"), logutil.WithLevelStr("warning"), logutil.WithCommonAttr(slog.String("service", "payments"), ) if err != nil { fmt.Println(err) return } // SlogLogger returns a *slog.Logger writing in the configured format. // SlogDefaultLogger additionally installs it as the slog default. logger := cfg.SlogLogger() fmt.Println(logutil.LevelName(cfg.Level), logger != nil) // Output: // warning true ``` -------------------------------- ### Install PPROF Tool Source: https://github.com/tecnickcom/nurago/blob/main/examples/service/README.md Command to install the pprof tool for analyzing profiling data. ```bash go install github.com/google/pprof@latest ``` -------------------------------- ### Initialize and Use Sleuth Client Source: https://github.com/tecnickcom/nurago/blob/main/pkg/sleuth/README.md Demonstrates how to initialize the client, perform a health check, and register a deployment. ```go c, err := sleuth.New("https://app.sleuth.io/api/1", "my-org", apiKey) if err != nil { return err } if err := c.HealthCheck(ctx); err != nil { return err } err = c.SendDeployRegistration(ctx, &sleuth.DeployRegistrationRequest{ Deployment: "my-service", Sha: "abcdef1234567890abcdef1234567890abcdef12", }) if err != nil { return err } ``` -------------------------------- ### DateTime marshaling example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/timeutil/README.md A complete example showing the marshaling of a DateTime object to a JSON string. ```go dt := timeutil.DateTime[timeutil.TRFC3339](time.Date(2023, 1, 2, 15, 4, 5, 0, time.UTC)) b, err := json.Marshal(dt) if err != nil { log.Fatal(err) } fmt.Println(string(b)) // Output: "2023-01-02T15:04:05Z" ``` -------------------------------- ### Password Hashing and Verification Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/passwordhash/README.md Demonstrates how to initialize the passwordhash provider with custom options, hash a password, and verify both correct and incorrect passwords. ```go opts := []passwordhash.Option{ passwordhash.WithKeyLen(32), passwordhash.WithSaltLen(16), passwordhash.WithTime(3), passwordhash.WithMemory(16_384), passwordhash.WithThreads(1), passwordhash.WithMinPasswordLength(16), passwordhash.WithMaxPasswordLength(128), } p := passwordhash.New(opts...) secret := "Example-Password-01" hash, err := p.PasswordHash(secret) if err != nil { log.Fatal(err) } ok, err := p.PasswordVerify(secret, hash) if err != nil { log.Fatal(err) } fmt.Println(ok) ok, err = p.PasswordVerify("Example-Wrong-Password-01", hash) if err != nil { log.Fatal(err) } fmt.Println(ok) // Output: // true // false ``` -------------------------------- ### Install jv validator Source: https://github.com/tecnickcom/nurago/blob/main/examples/service/doc/CONFIG.md Install the jv program to validate configuration files against JSON schemas. ```bash go install github.com/santhosh-tekuri/jsonschema/cmd/jv@latest ``` -------------------------------- ### Full Validator Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/validator/README.md A complete example showing the instantiation of a validator and the validation of a complex nested data structure. ```go // data structure to check validObj := RootStruct{ BoolField: true, SubStr: SubStruct{ URLField: "http://first.test.invalid", IntField: 3, }, SubStrPtr: &SubStruct{ URLField: "http://second.test.invalid", IntField: 123, }, StringField: "hello world", NoNameField: "test", } // instantiate the validator object v, err := validator.New( validator.WithFieldNameTag(fieldTagName), validator.WithCustomValidationTags(validator.CustomValidationTags()), validator.WithErrorTemplates(validator.ErrorTemplates()), ) if err != nil { log.Fatal(err) } // check the data structure err = v.ValidateStruct(validObj) if err != nil { log.Fatal(err) } fmt.Println("OK") // Output: // OK ``` -------------------------------- ### Initialize and use the OpenTelemetry client Source: https://github.com/tecnickcom/nurago/blob/main/pkg/metrics/opentel/README.md This example demonstrates initializing the client with custom provider functions and using it to instrument an HTTP handler and record metrics. The provided meter and tracer functions are configured to discard output, suitable for testing environments. ```go // The default providers export over OTLP. The example substitutes // providers that discard their output, so it needs no collector. // Production code omits both options and configures the exporter through // the standard OTEL_EXPORTER_OTLP_* environment variables. meterFn := func(_ context.Context, res *sdkresource.Resource) (*sdkmetric.MeterProvider, error) { return sdkmetric.NewMeterProvider( sdkmetric.WithResource(res), sdkmetric.WithReader(sdkmetric.NewManualReader()), ), nil } tracerFn := func(_ context.Context, res *sdkresource.Resource) (*sdktrace.TracerProvider, error) { return sdktrace.NewTracerProvider(sdktrace.WithResource(res)), nil } // The returned Client satisfies metrics.Client, so application code // depends on the contract rather than on OpenTelemetry. var client metrics.Client client, err := opentel.New( context.TODO(), "payments", "v1.2.3", opentel.WithMeterProviderFn(meterFn), opentel.WithTracerProviderFn(tracerFn), ) if err != nil { fmt.Println(err) return } defer func() { _ = client.Close() }() // The path label must be a low-cardinality route template, never a raw // request URI containing identifiers. handler := client.InstrumentHandler("/users/{id}", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }) rec := httptest.NewRecorder() handler.ServeHTTP(rec, httptest.NewRequestWithContext( context.TODO(), http.MethodGet, "/users/42", nil, )) client.IncErrorCounter("user", "read", "404") // OpenTelemetry is push-based, so the metrics endpoint exposes no // scrape payload and answers with a health-style 200. scrape := httptest.NewRecorder() client.MetricsHandlerFunc()(scrape, httptest.NewRequestWithContext( context.TODO(), http.MethodGet, "/metrics", nil, )) fmt.Println(rec.Code, scrape.Code) // Output: // 200 200 ``` -------------------------------- ### Translate vanity phone numbers Source: https://github.com/tecnickcom/nurago/blob/main/pkg/phonekeypad/README.md Use KeypadNumberString to get a dialable string or KeypadNumber to get a slice of integers. ```go numStr := phonekeypad.KeypadNumberString("1-800-FLOWERS") // numStr == "18003569377" digits := phonekeypad.KeypadNumber("1-800-FLOWERS") // digits == []int{1, 8, 0, 0, 3, 5, 6, 9, 3, 7, 7} ``` -------------------------------- ### Retrier Execution Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/retrier/README.md A complete example showing a task that succeeds on the third attempt using specific retry options. ```go var count int // example function that returns nil only at the third attempt. task := func(_ context.Context) error { if count == 2 { return nil } count++ return errors.New("ERROR") } opts := []retrier.Option{ retrier.WithRetryIfFn(retrier.DefaultRetryIf), retrier.WithAttempts(5), retrier.WithDelay(10 * time.Millisecond), retrier.WithDelayFactor(1.1), retrier.WithJitter(5 * time.Millisecond), retrier.WithTimeout(2 * time.Millisecond), } r, err := retrier.New(opts...) if err != nil { log.Fatal(err) } timeout := 1 * time.Second ctx, cancel := context.WithTimeout(context.TODO(), timeout) err = r.Run(ctx, task) cancel() if err != nil { log.Fatal(err) } fmt.Println(count) // Output: // 2 ``` -------------------------------- ### sqlconn.New with Mock Database Source: https://github.com/tecnickcom/nurago/blob/main/pkg/sqlconn/README.md Demonstrates initializing a connection with custom pool settings and a mock SQL open function for testing purposes. ```go // A real program registers a driver (for example go-sql-driver/mysql) // and lets sqlconn call sql.Open. WithSQLOpenFunc substitutes a mock so // the example needs no database. mockDB, mock, err := sqlmock.New() if err != nil { fmt.Println(err) return } // The connection check runs the validation query, and Shutdown closes // the pool. mock.ExpectQuery("SELECT 1").WillReturnRows(sqlmock.NewRows([]string{"1"}).AddRow(1)) mock.ExpectClose() conn, err := sqlconn.New( context.TODO(), "mysql", "user:pass@tcp(127.0.0.1:3306)/testdb", sqlconn.WithConnMaxOpen(25), sqlconn.WithConnMaxIdleCount(5), sqlconn.WithConnMaxLifetime(5*time.Minute), sqlconn.WithPingTimeout(2*time.Second), sqlconn.WithSQLOpenFunc(func(_, _ string) (*sql.DB, error) { return mockDB, nil }), ) if err != nil { fmt.Println(err) return } defer func() { _ = conn.Shutdown(context.TODO()) }() // DB returns the pooled *sql.DB for normal query execution. fmt.Println(conn.DB() != nil) // Output: // true ``` -------------------------------- ### Register Deployment with Mock Server Source: https://github.com/tecnickcom/nurago/blob/main/pkg/sleuth/README.md An example showing how to use a test server to verify deployment registration requests, including payload validation. ```go // A stand-in for https://app.sleuth.io. Real code passes the Sleuth // base address. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println(r.Method, r.URL.Path) w.WriteHeader(http.StatusOK) })) defer srv.Close() client, err := sleuth.New(srv.URL, "example-org", "api-key") if err != nil { fmt.Println(err) return } // Requests are validated before being sent, so a malformed payload // fails locally rather than at the API. err = client.SendDeployRegistration(context.TODO(), &sleuth.DeployRegistrationRequest{ Deployment: "payments-production", Sha: "9f8c1b2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b", Environment: "production", IgnoreIfDuplicate: true, Tags: []string{"#payments", "#backend"}, }) fmt.Println("err:", err) // Output: // POST /deployments/example-org/payments-production/register_deploy // err: ``` -------------------------------- ### Periodic Job Execution Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/periodic/README.md A complete example showing the creation, execution, and stopping of a periodic job, including the expected output. ```go count := make(chan int, 1) count <- 0 // example task to execute periodically task := func(_ context.Context) { v := <-count count <- (v + 1) } interval := 20 * time.Millisecond jitter := 2 * time.Millisecond timeout := 2 * time.Millisecond // create a new periodic job p, err := periodic.New(interval, jitter, timeout, task) if err != nil { close(count) log.Fatal(err) } // start the periodic job p.Start(context.TODO()) // wait for 3 times the interval wait := 3 * interval time.Sleep(wait) // stop the periodic job p.Stop() fmt.Println(<-count) close(count) // Output: // 3 ``` -------------------------------- ### Self-Contained SQS Example Source: https://github.com/tecnickcom/nurago/blob/main/pkg/sqs/README.md A complete example using an injected SQS client to send, receive, and delete a message, including the expected output. ```go // A caller would normally configure a real client via options such as // WithAWSOptions or WithEndpointMutable (and the region would be derived from // the queue URL); here an injected client keeps the example self-contained, so // no AWS configuration is loaded. c, err := sqs.New( context.TODO(), "https://sqs.us-east-1.amazonaws.com/123456789012/my-queue", "", // standard (non-FIFO) queue: no message group ID sqs.WithSQSClient(&exampleSQSClient{}), ) if err != nil { fmt.Println("error:", err) return } err = c.Send(context.TODO(), "hello world") if err != nil { fmt.Println("error:", err) return } msg, err := c.Receive(context.TODO()) if err != nil { fmt.Println("error:", err) return } fmt.Println(msg.Body) // After processing, acknowledge the message by deleting it. err = c.Delete(context.TODO(), msg.ReceiptHandle) if err != nil { fmt.Println("error:", err) return } // Output: // hello world ``` -------------------------------- ### Initialize and Query enumdb Source: https://github.com/tecnickcom/nurago/blob/main/pkg/enumdb/README.md Demonstrates initializing enumdb with a database connection and queries, followed by performing ID and name lookups. ```go // A real program would use a *sql.DB from sql.Open. The mock keeps the // example self-contained and its output deterministic. db, mock, err := sqlmock.New() if err != nil { fmt.Println(err) return } defer func() { _ = db.Close() }() mock.ExpectQuery("SELECT id, name FROM status").WillReturnRows( sqlmock.NewRows([]string{"id", "name"}). AddRow(1, "pending"). AddRow(2, "active"). AddRow(3, "archived"), ) // One query per enumeration table, each returning (id int, name string). queries := enumdb.EnumTableQuery{ "status": "SELECT id, name FROM status WHERE disabled = 0 ORDER BY id", } enum, err := enumdb.New(context.TODO(), db, queries) if err != nil { fmt.Println(err) return } // The result is keyed by table name and each value is a thread-safe // bidirectional cache, ready for lookups without further database access. name, err := enum["status"].Name(2) fmt.Println(name, err) id, err := enum["status"].ID("archived") fmt.Println(id, err) fmt.Println(enum["status"].SortNames()) // Output: // active // 3 // [active archived pending] ``` -------------------------------- ### MySQL Example Table Schema Source: https://github.com/tecnickcom/nurago/blob/main/pkg/enumdb/README.md An example of a MySQL database table structure compatible with the enumdb package, featuring id and name columns. ```sql CREATE TABLE IF NOT EXISTS `example` ( `id` SMALLINT UNSIGNED NOT NULL, `name` VARCHAR(50) NOT NULL, `disabled` TINYINT NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE INDEX `id_UNIQUE` (`id` ASC), UNIQUE INDEX `name_UNIQUE` (`name` ASC)) ENGINE = InnoDB COMMENT = 'Example enumeration table'; ``` -------------------------------- ### Initialize and use sfcache Source: https://github.com/tecnickcom/nurago/blob/main/pkg/sfcache/README.md Demonstrates creating a new cache instance with a lookup function and performing a lookup operation. ```go cache := sfcache.New(func(ctx context.Context, key string) (*Customer, error) { return fetchCustomer(ctx, key) }, sfcache.Config{Size: 256, TTL: 5 * time.Minute}) customer, err := cache.Lookup(ctx, "customer:123") ```