Go SDK
Installation, configuration, and API reference for the Sluice Go SDK.
Sluice SDK -- Go
Installation
go get github.com/ontopix/sluice/go
Configuration
DefaultConfig
import sluice "github.com/ontopix/sluice/go"
cfg := sluice.DefaultConfig()
Returns a Config with:
type Config struct {
TableName string // "ontopix-vendor-buckets-prod"
Region string // "eu-central-1"
EndpointURL string // "" (empty = standard AWS endpoint)
LeaseTTL time.Duration // 60s
MaxRetries int // 3
DefaultSlotTimeout time.Duration // 30s
LogLevel string // "INFO"
}
ConfigFromEnv
cfg := sluice.ConfigFromEnv()
Reads these environment variables, falling back to the defaults above:
| Variable | Type | Default |
|---|---|---|
SLUICE_TABLE_NAME | string | "ontopix-vendor-buckets-prod" |
SLUICE_AWS_REGION | string | "eu-central-1" |
SLUICE_ENDPOINT_URL | string | "" |
SLUICE_LEASE_TTL | int (seconds) | 60 |
SLUICE_MAX_RETRIES | int | 3 |
SLUICE_DEFAULT_SLOT_TIMEOUT | float (seconds) | 30.0 |
SLUICE_LOG_LEVEL | string | "INFO" |
WithConfig option
Pass a custom config to any function using the WithConfig option:
cfg := sluice.Config{
TableName: "my-custom-table",
Region: "us-east-1",
MaxRetries: 5,
LeaseTTL: 120 * time.Second,
}
err := sluice.WithSlot(ctx, "openai#gpt-4o#requests", 10*time.Second, fn, sluice.WithConfig(cfg))
When no WithConfig option is passed, ConfigFromEnv() is called automatically.
WithSlot -- callback API (recommended)
WithSlot acquires a slot, runs the callback, and guarantees release on return (success or error). This is the safest API because release cannot be forgotten.
import (
"context"
"time"
sluice "github.com/ontopix/sluice/go"
)
err := sluice.WithSlot(ctx, "openai#gpt-4o#requests", 10*time.Second,
func(ctx context.Context) error {
resp, err := callOpenAI(ctx, prompt)
if err != nil {
return err
}
// process resp
return nil
},
)
Signature
func WithSlot(
ctx context.Context,
dimension string,
timeout time.Duration,
fn func(context.Context) error,
opts ...Option,
) error
Multiple dimensions
WithSlotMany acquires slots for all dimensions atomically:
err := sluice.WithSlotMany(ctx,
[]string{"openai#gpt-4o#requests", "openai#gpt-4o#tokens"},
15*time.Second,
func(ctx context.Context) error {
return callOpenAI(ctx, prompt)
},
)
Signature
func WithSlotMany(
ctx context.Context,
dimensions []string,
timeout time.Duration,
fn func(context.Context) error,
opts ...Option,
) error
Slot -- handle API
Slot returns a SlotHandle that the caller must release explicitly. Use defer to ensure release.
handle, err := sluice.Slot(ctx, "openai#gpt-4o#requests", 10*time.Second)
if err != nil {
return err
}
defer handle.Release(ctx)
resp, err := callOpenAI(ctx, prompt)
Signatures
func Slot(
ctx context.Context,
dimension string,
timeout time.Duration,
opts ...Option,
) (*SlotHandle, error)
func SlotMany(
ctx context.Context,
dimensions []string,
timeout time.Duration,
opts ...Option,
) (*SlotHandle, error)
SlotHandle
type SlotHandle struct { /* ... */ }
func (h *SlotHandle) Release(ctx context.Context) error
Acquire / Release -- low-level API
Acquire performs a single attempt to obtain a slot. It returns immediately with either Granted or RetryIn. The caller is responsible for retry logic and calling Release.
result, err := sluice.Acquire(ctx, "openai#gpt-4o#requests")
if err != nil {
return err
}
if result.Outcome == sluice.Granted {
defer result.Release(ctx)
resp, err := callOpenAI(ctx, prompt)
// ...
} else {
fmt.Printf("Retry after %.1fs\n", result.WaitSeconds)
}
Signatures
func Acquire(
ctx context.Context,
dimension string,
opts ...Option,
) (*AcquireResult, error)
func AcquireMany(
ctx context.Context,
dimensions []string,
opts ...Option,
) (*AcquireResult, error)
AcquireMany is all-or-nothing: if any dimension has insufficient tokens, none are acquired and a single RetryIn result is returned with the maximum wait time.
AcquireResult
type AcquireResult struct {
Outcome AcquireOutcome
WaitSeconds float64
LeaseKey string
Dimension string
}
func (r *AcquireResult) Release(ctx context.Context) error
AcquireOutcome
const (
Granted AcquireOutcome = "granted"
RetryIn AcquireOutcome = "retry_in"
)
Penalize
Reduces the token count for a dimension by a factor. Use this when a vendor returns 429 despite the slot being granted.
Unlike the Python and TypeScript SDKs, the Go SDK returns the error rather than swallowing it.
err := sluice.Penalize(ctx, "openai#gpt-4o#requests", 0.8)
if err != nil {
log.Printf("penalize failed: %v", err)
}
Signature
func Penalize(
ctx context.Context,
dimension string,
factor float64, // 0.0 to 1.0
opts ...Option,
) error
Error handling
SlotTimeout
Returned by Slot, SlotMany, WithSlot, and WithSlotMany when the timeout expires.
handle, err := sluice.Slot(ctx, "openai#gpt-4o#requests", 5*time.Second)
if err != nil {
var timeout sluice.SlotTimeout
if errors.As(err, &timeout) {
// Handle timeout
}
return err
}
defer handle.Release(ctx)
ConfigurationError
Returned when a dimension is not found in the DynamoDB table.
result, err := sluice.Acquire(ctx, "nonexistent#dimension")
if err != nil {
var cfgErr *sluice.ConfigurationError
if errors.As(err, &cfgErr) {
fmt.Println("Missing dimension:", cfgErr.Dimension)
}
}
Context cancellation
All functions accept a context.Context. If the context is cancelled or its deadline is exceeded, the function returns immediately with ctx.Err(). The Slot family of functions internally creates a child context with a deadline set to now + timeout.
Client -- connection reuse
Package-level functions (WithSlot, Acquire, etc.) create a new DynamoDB connection on each call. For multiple calls within the same process, use Client to hold the connection:
client, err := sluice.NewClient(ctx)
if err != nil {
return err
}
err = client.WithSlot(ctx, "openai#gpt-4o#requests", 10*time.Second,
func(ctx context.Context) error {
_, err := callOpenAI(ctx, prompt)
return err
},
)
NewClient accepts the same ...Option arguments as other functions:
client, err := sluice.NewClient(ctx, sluice.WithConfig(sluice.Config{
MaxRetries: 5,
}))
The client provides the same methods as the package-level functions: Acquire, AcquireMany, WithSlot, WithSlotMany, Slot, SlotMany, Penalize.
Full example
package main
import (
"context"
"errors"
"fmt"
"time"
sluice "github.com/ontopix/sluice/go"
)
func callWithRateLimit(ctx context.Context, prompt string) (string, error) {
var response string
err := sluice.WithSlot(ctx, "openai#gpt-4o#requests", 10*time.Second,
func(ctx context.Context) error {
var err error
response, err = callOpenAI(ctx, prompt)
return err
},
)
return response, err
}
func callWithBackpressure(ctx context.Context, prompt string) (string, error) {
var response string
err := sluice.WithSlot(ctx, "openai#gpt-4o#requests", 10*time.Second,
func(ctx context.Context) error {
var err error
response, err = callOpenAI(ctx, prompt)
if err != nil && isRateLimitError(err) {
_ = sluice.Penalize(ctx, "openai#gpt-4o#requests", 0.5)
}
return err
},
)
return response, err
}