Documentation
¶
Overview ¶
Package agent is foony-sync: the customer-run Database Sync agent. It holds the customer's database credentials AND its live-query definitions locally (neither ever reaches foony), captures row changes over logical replication, recomputes the queries, and publishes the resulting docs to the app's reserved db: channels. The only inbound traffic it acts on is a warm request naming a channel. See https://foony.io/docs/database-sync.
Index ¶
- func Run(ctx context.Context, cfg Config) error
- type Config
- type FileConfig
- type FoonyClient
- func (client *FoonyClient) AgentKey() string
- func (client *FoonyClient) KeyID() string
- func (client *FoonyClient) LiveDocs(ctx context.Context) ([]string, bool, error)
- func (client *FoonyClient) PublishDoc(ctx context.Context, channel string, doc json.RawMessage) error
- func (client *FoonyClient) SendHeartbeat(ctx context.Context, heartbeat Heartbeat) error
- type Heartbeat
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Config ¶
type Config struct {
// FoonyURL is the realtime data-plane base URL (https://realtime.foony.io).
FoonyURL string
// AgentKey is the source credential from the dashboard (appSlug.keyId:secret).
AgentKey string
// DatabaseURL is the customer Postgres DSN. The agent adds
// replication=database itself for the WAL connection.
DatabaseURL string
// ConfigPath is the local definitions file (foony-sync.json).
ConfigPath string
// Version is the agent build version, reported on heartbeats.
Version string
Logger *slog.Logger
}
Config is everything foony-sync needs: where foony is, the source credential, the customer database, and the local definitions file.
type FileConfig ¶
type FileConfig struct {
Queries []spec.Query `json:"queries"`
// StatementTimeoutMs pins every query the agent runs (default 5000).
StatementTimeoutMs int `json:"statementTimeoutMs,omitempty"`
// WalRetentionCapBytes is the safety valve: past this much retained WAL
// the agent recycles its replication slot (drop, re-attach, recompute
// every live doc) rather than risk filling the database's disk. Bulk
// writes on a large table can cross it in under a minute, so raise it for
// a planned migration instead of disabling it (default 4 GiB; 0 keeps the
// default, -1 disables).
WalRetentionCapBytes int64 `json:"walRetentionCapBytes,omitempty"`
}
FileConfig is the agent's local config file (foony-sync.json): the live queries plus the two protect-my-database knobs. Definitions live here, next to the code that owns the schema, and never leave the machine; the agent reports only name and table summaries to the dashboard.
func LoadConfig ¶
func LoadConfig(path string) (FileConfig, error)
LoadConfig reads and validates the agent config file. Every query is checked with the same rules the docs describe, so a typo fails fast at startup with a message naming the query.
type FoonyClient ¶
type FoonyClient struct {
// contains filtered or unexported fields
}
FoonyClient talks to foony for the agent: the dbsync control endpoints (heartbeats and live-doc listing) over plain REST, and doc publishes through the realtime SDK's Rest client, all authenticated with the source's api key.
func NewFoonyClient ¶
func NewFoonyClient(baseURL, agentKey string) (*FoonyClient, error)
NewFoonyClient parses the agent key (appSlug.keyId:secret) into Basic credentials for baseURL.
func (*FoonyClient) AgentKey ¶
func (client *FoonyClient) AgentKey() string
AgentKey returns the full credential (appSlug.keyId:secret) for the WebSocket handshake, which authenticates with the key directly: key auth is what opens the reserved dbsync: namespace.
func (*FoonyClient) KeyID ¶
func (client *FoonyClient) KeyID() string
KeyID returns the public key id of the agent credential, the stable local identity the replication slot name derives from.
func (*FoonyClient) LiveDocs ¶
LiveDocs lists the db: channels that currently have subscribers, gathered from the edge fleet. The bool reports whether the view is complete; a truncated view must only extend the agent's live set, never shrink it.
func (*FoonyClient) PublishDoc ¶
func (client *FoonyClient) PublishDoc(ctx context.Context, channel string, doc json.RawMessage) error
PublishDoc publishes a computed doc to its db: channel through the realtime SDK. The channel's built-in retained-last policy makes this both the live fan-out and the stored snapshot new subscribers replay.
func (*FoonyClient) SendHeartbeat ¶
func (client *FoonyClient) SendHeartbeat(ctx context.Context, heartbeat Heartbeat) error
SendHeartbeat reports agent health to the source's dashboard row.
type Heartbeat ¶
type Heartbeat struct {
AgentVersion string `json:"agentVersion"`
State string `json:"state"`
SlotLagBytes int64 `json:"slotLagBytes"`
DirtyDepth int64 `json:"dirtyDepth"`
LastEventAt *time.Time `json:"lastEventAt,omitempty"`
LastError string `json:"lastError,omitempty"`
Queries []spec.QuerySummary `json:"queries"`
}
Heartbeat is the body of POST /sync/heartbeat. Queries is a name-and-tables summary only: the definitions stay in the agent's local config.