Documentation
¶
Index ¶
- func BuildPostgresWriteQuery(table string, columns []string, rowCount int, mode PostgresWriteMode, ...) string
- func RecordToKafka(r types.Record) kafka.Message
- type AcksLevel
- type BlackholeSink
- type CheckpointedSink
- type DLQ
- type Describable
- type FailurePolicy
- type JSONSerializer
- type KafkaSink
- type KafkaSinkOption
- func KafkaSinkAsync() KafkaSinkOption
- func KafkaSinkBatchSize(n int) KafkaSinkOption
- func KafkaSinkBatchTimeout(d time.Duration) KafkaSinkOption
- func KafkaSinkBrokers(brokers ...string) KafkaSinkOption
- func KafkaSinkDLQ(dlq DLQ) KafkaSinkOption
- func KafkaSinkFailurePolicy(p FailurePolicy) KafkaSinkOption
- func KafkaSinkMaxRetries(n int) KafkaSinkOption
- func KafkaSinkRequiredAcks(level AcksLevel) KafkaSinkOption
- func KafkaSinkSASL(cfg auth.SASLConfig) KafkaSinkOption
- func KafkaSinkSerialize(s Serializer) KafkaSinkOption
- func KafkaSinkTLS(cfg auth.TLSConfig) KafkaSinkOption
- func KafkaSinkTopic(topic string) KafkaSinkOption
- type PostgresSink
- type PostgresSinkOption
- func PostgresBatchSize(n int) PostgresSinkOption
- func PostgresConflictColumns(cols ...string) PostgresSinkOption
- func PostgresDLQ(dlq DLQ) PostgresSinkOption
- func PostgresDSN(dsn string) PostgresSinkOption
- func PostgresFailurePolicy(p FailurePolicy) PostgresSinkOption
- func PostgresFlushInterval(d time.Duration) PostgresSinkOption
- func PostgresMapper(m RecordMapper) PostgresSinkOption
- func PostgresMaxRetries(n int) PostgresSinkOption
- func PostgresMode(mode PostgresWriteMode) PostgresSinkOption
- func PostgresUpdateColumns(cols ...string) PostgresSinkOption
- type PostgresWriteMode
- type RecordMapper
- type Serializer
- type SerializerFunc
- type Sink
- type SinkInfo
- type StdoutSink
- type TxnKafkaOption
- func TxnKafkaBrokers(brokers ...string) TxnKafkaOption
- func TxnKafkaMarkerTopic(topic string) TxnKafkaOption
- func TxnKafkaSASL(cfg auth.SASLConfig) TxnKafkaOption
- func TxnKafkaSerialize(s Serializer) TxnKafkaOption
- func TxnKafkaTLS(cfg auth.TLSConfig) TxnKafkaOption
- func TxnKafkaTopic(topic string) TxnKafkaOption
- func TxnKafkaTransactionalID(id string) TxnKafkaOption
- type TxnKafkaSink
- func (s *TxnKafkaSink) Abort(ctx context.Context, id string) error
- func (s *TxnKafkaSink) Commit(ctx context.Context, id string) error
- func (s *TxnKafkaSink) Describe() SinkInfo
- func (s *TxnKafkaSink) SetOnPrepared(fn func(id string, err error))
- func (s *TxnKafkaSink) TransactionalID() string
- func (s *TxnKafkaSink) WasCommitted(ctx context.Context, id string) (bool, error)
- func (s *TxnKafkaSink) Write(ctx context.Context, in <-chan types.Record) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildPostgresWriteQuery ¶ added in v0.5.0
func BuildPostgresWriteQuery(table string, columns []string, rowCount int, mode PostgresWriteMode, conflictColumns, updateColumns []string) string
BuildPostgresWriteQuery constructs the SQL used by PostgresSink. It is exported for tests and SQL inspection; callers should still use NewPostgresSink for actual writes.
Types ¶
type AcksLevel ¶
type AcksLevel int
AcksLevel controls how many broker acknowledgements the Kafka sink waits for before considering a write successful.
type BlackholeSink ¶
type BlackholeSink struct {
// contains filtered or unexported fields
}
BlackholeSink discards all records. Used for benchmarking pipeline throughput without the overhead of writing to an external system.
func NewBlackholeSink ¶
func NewBlackholeSink() *BlackholeSink
NewBlackholeSink creates a sink that silently discards all records.
func (*BlackholeSink) Count ¶
func (s *BlackholeSink) Count() int64
Count returns the total number of records consumed.
type CheckpointedSink ¶ added in v0.4.0
type CheckpointedSink interface {
Sink
// SetOnPrepared registers the coordinator callback invoked when a
// barrier's output is fully staged (or staging failed).
SetOnPrepared(fn func(id string, err error))
// Commit finalizes the transaction for checkpoint id and unblocks Write.
Commit(ctx context.Context, id string) error
// Abort discards the transaction for checkpoint id and unblocks Write.
Abort(ctx context.Context, id string) error
// WasCommitted reports whether checkpoint id's transaction
// committed before a crash.
WasCommitted(ctx context.Context, id string) (bool, error)
}
CheckpointedSink is a Sink that participates in coordinated exactly-once checkpoints. Output between two checkpoint barriers is staged (e.g. in a Kafka transaction) and becomes visible only when the coordinator calls Commit.
Contract:
- Write sees checkpoint barriers in-band, after every pre-barrier record. On a barrier the sink must flush all staged output for the ending interval into the open transaction (plus a transaction marker identifying the checkpoint), invoke the OnPrepared callback, and BLOCK further writes until the coordinator calls Commit or Abort for that checkpoint.
- Commit makes the interval's output visible and opens the next transaction. Abort discards it.
- WasCommitted reports, after a restart, whether the transaction for a checkpoint ID actually committed (e.g. by probing the transaction marker under read-committed isolation). It resolves the prepared-but-unconfirmed recovery case.
type DLQ ¶ added in v0.4.0
DLQ is a sink that receives records that could not be written to the primary sink after all retries. It is used together with FailurePolicyDLQ.
Common DLQ implementations: a separate Kafka topic, a file on disk, or a Postgres error table.
type Describable ¶
type Describable interface {
Describe() SinkInfo
}
Describable is an optional interface that Sinks can implement to expose metadata for the dashboard.
type FailurePolicy ¶ added in v0.4.0
type FailurePolicy int
FailurePolicy determines what happens when a sink write fails after all retry attempts have been exhausted.
const ( // FailurePolicyDrop silently discards the record. FailurePolicyDrop FailurePolicy = iota // FailurePolicyDLQ forwards the record to a dead-letter-queue sink. FailurePolicyDLQ // FailurePolicyFail returns an error and stops the pipeline. FailurePolicyFail )
type JSONSerializer ¶
type JSONSerializer struct{}
JSONSerializer marshals Record.Parsed (if set) or Record.Value to JSON. When Parsed is nil and Value is already JSON bytes, this effectively passes them through (re-encoded, which is a no-op for valid JSON).
func NewJSONSerializer ¶
func NewJSONSerializer() *JSONSerializer
NewJSONSerializer creates a JSON serializer.
type KafkaSink ¶
type KafkaSink struct {
// contains filtered or unexported fields
}
KafkaSink writes records to a single Kafka topic. It implements the Sink interface for use in mailer pipelines.
Configure a KafkaSink with functional options via NewKafkaSink:
sink := sink.NewKafkaSink(
sink.KafkaSinkBrokers("localhost:9092"),
sink.KafkaSinkTopic("order-summary"),
sink.KafkaSinkBatchSize(200),
sink.KafkaSinkRequiredAcks(sink.AcksAll),
sink.KafkaSinkSASL(auth.SASLConfig{Mechanism: auth.SASLPlain, Username: "u", Password: "p"}),
sink.KafkaSinkSerialize(sink.NewJSONSerializer()),
)
Records are written in batches for efficiency. On context cancellation, the sink drains remaining records for up to 5 seconds before flushing.
mailer.Record fields are mapped to kafka.Message as follows:
- Key -> Message.Key
- Value -> Message.Value (or serializer output if configured)
- Timestamp -> Message.Time
- Headers -> Message.Headers
func NewKafkaSink ¶
func NewKafkaSink(opts ...KafkaSinkOption) *KafkaSink
NewKafkaSink creates a Sink that writes to a Kafka topic. Brokers and Topic are required; if missing, NewKafkaSink panics.
func (*KafkaSink) Write ¶
Write reads records from the input channel and writes them to Kafka. It batches records for efficiency. On write failure, the batch is retried up to cfg.maxRetries times with exponential backoff. After all retries are exhausted, the failure policy is applied to each record in the batch.
On context cancellation, the sink drains remaining records for up to shutdownTimeout before performing a final flush.
type KafkaSinkOption ¶
type KafkaSinkOption func(*kafkaSinkConfig)
KafkaSinkOption configures a KafkaSink. Pass one or more to NewKafkaSink. Brokers and Topic are required.
func KafkaSinkAsync ¶
func KafkaSinkAsync() KafkaSinkOption
KafkaSinkAsync enables asynchronous writes — WriteMessages returns immediately without waiting for acknowledgement. Improves throughput but offers no durability guarantee on failure.
func KafkaSinkBatchSize ¶
func KafkaSinkBatchSize(n int) KafkaSinkOption
KafkaSinkBatchSize sets the max messages per batch (default 100). Larger batches improve throughput at the cost of latency.
func KafkaSinkBatchTimeout ¶
func KafkaSinkBatchTimeout(d time.Duration) KafkaSinkOption
KafkaSinkBatchTimeout sets the max wait before flushing a partial batch (default 1s). This bounds latency even when the batch is not full.
func KafkaSinkBrokers ¶
func KafkaSinkBrokers(brokers ...string) KafkaSinkOption
KafkaSinkBrokers sets the Kafka bootstrap brokers. Required. Example: KafkaSinkBrokers("localhost:9092").
func KafkaSinkDLQ ¶ added in v0.4.0
func KafkaSinkDLQ(dlq DLQ) KafkaSinkOption
KafkaSinkDLQ sets the dead-letter-queue for failed records. Only used when KafkaSinkFailurePolicy is set to FailurePolicyDLQ.
func KafkaSinkFailurePolicy ¶ added in v0.4.0
func KafkaSinkFailurePolicy(p FailurePolicy) KafkaSinkOption
KafkaSinkFailurePolicy sets what happens when a record fails after all retries. Default is FailurePolicyDrop (record is silently discarded).
func KafkaSinkMaxRetries ¶ added in v0.4.0
func KafkaSinkMaxRetries(n int) KafkaSinkOption
KafkaSinkMaxRetries sets the number of times a failed write is retried before the failure policy is applied (default 3).
func KafkaSinkRequiredAcks ¶
func KafkaSinkRequiredAcks(level AcksLevel) KafkaSinkOption
KafkaSinkRequiredAcks sets the acknowledgement level (default AcksLeader).
func KafkaSinkSASL ¶
func KafkaSinkSASL(cfg auth.SASLConfig) KafkaSinkOption
KafkaSinkSASL enables SASL authentication on the Kafka connection.
func KafkaSinkSerialize ¶
func KafkaSinkSerialize(s Serializer) KafkaSinkOption
KafkaSinkSerialize sets a Serializer that runs on every record before it is written to Kafka. If Record.Parsed is set, the serializer receives it; otherwise it receives Record.Value. The serializer's output replaces Record.Value in the Kafka message.
func KafkaSinkTLS ¶
func KafkaSinkTLS(cfg auth.TLSConfig) KafkaSinkOption
KafkaSinkTLS enables TLS on the Kafka connection.
func KafkaSinkTopic ¶
func KafkaSinkTopic(topic string) KafkaSinkOption
KafkaSinkTopic sets the destination topic. Required.
type PostgresSink ¶
type PostgresSink struct {
// contains filtered or unexported fields
}
PostgresSink writes records to a Postgres database in batches. It implements the Sink interface for use in mailer pipelines.
Configure a PostgresSink with functional options via NewPostgresSink:
sink := sink.NewPostgresSink(
sink.PostgresDSN("postgres://user:pass@localhost:5432/dbname?sslmode=disable"),
sink.PostgresMapper(func(r types.Record) (string, []string, []any) {
o := r.Parsed.(*Order)
return "orders",
[]string{"order_id", "customer", "amount"},
[]any{o.OrderID, o.Customer, o.Amount}
}),
sink.PostgresBatchSize(500),
)
Records are accumulated and inserted in batches using multi-value INSERT statements for efficiency. On context cancellation, the sink drains remaining records for up to 5 seconds before flushing the final batch.
func NewPostgresSink ¶
func NewPostgresSink(opts ...PostgresSinkOption) *PostgresSink
NewPostgresSink creates a Sink that writes to Postgres. DSN and a RecordMapper are required; if missing, NewPostgresSink panics.
The connection pool is created immediately. If the database is unreachable, NewPostgresSink panics to fail fast at construction time.
func (*PostgresSink) Describe ¶
func (p *PostgresSink) Describe() SinkInfo
Describe returns metadata about this Postgres sink for the dashboard.
type PostgresSinkOption ¶
type PostgresSinkOption func(*postgresSinkConfig)
PostgresSinkOption configures a PostgresSink. Pass one or more to NewPostgresSink. DSN and a RecordMapper are required.
func PostgresBatchSize ¶
func PostgresBatchSize(n int) PostgresSinkOption
PostgresBatchSize sets the max records per INSERT batch (default 100). Larger batches reduce round-trips but increase memory usage.
func PostgresConflictColumns ¶ added in v0.5.0
func PostgresConflictColumns(cols ...string) PostgresSinkOption
PostgresConflictColumns sets the ON CONFLICT target for upserts.
func PostgresDLQ ¶ added in v0.4.0
func PostgresDLQ(dlq DLQ) PostgresSinkOption
PostgresDLQ sets the dead-letter-queue for failed records. Only used when PostgresFailurePolicy is set to FailurePolicyDLQ.
func PostgresDSN ¶
func PostgresDSN(dsn string) PostgresSinkOption
PostgresDSN sets the Postgres connection string. Required. Example: "postgres://user:pass@localhost:5432/dbname?sslmode=disable".
func PostgresFailurePolicy ¶ added in v0.4.0
func PostgresFailurePolicy(p FailurePolicy) PostgresSinkOption
PostgresFailurePolicy sets what happens when a row fails after all retries. Default is FailurePolicyDrop (row is silently discarded).
func PostgresFlushInterval ¶
func PostgresFlushInterval(d time.Duration) PostgresSinkOption
PostgresFlushInterval sets the max wait before flushing a partial batch (default 5s). Bounds latency even when the batch is not full.
func PostgresMapper ¶
func PostgresMapper(m RecordMapper) PostgresSinkOption
PostgresMapper sets the function that maps each Record to a table, column list, and value list. Required.
func PostgresMaxRetries ¶
func PostgresMaxRetries(n int) PostgresSinkOption
PostgresMaxRetries sets the number of times a failed batch insert is retried before giving up (default 3).
func PostgresMode ¶ added in v0.5.0
func PostgresMode(mode PostgresWriteMode) PostgresSinkOption
PostgresMode sets whether writes use plain INSERT or INSERT ... ON CONFLICT DO UPDATE. Default is PostgresInsert.
func PostgresUpdateColumns ¶ added in v0.5.0
func PostgresUpdateColumns(cols ...string) PostgresSinkOption
PostgresUpdateColumns sets the columns updated from EXCLUDED values on conflict. If omitted in upsert mode, all non-conflict inserted columns are updated.
type PostgresWriteMode ¶ added in v0.5.0
type PostgresWriteMode string
PostgresWriteMode selects how rows are written.
const ( PostgresInsert PostgresWriteMode = "insert" PostgresUpsert PostgresWriteMode = "upsert" )
type RecordMapper ¶
RecordMapper extracts the table name, column names, and values from a Record. The returned columns and values must be the same length and in the same order.
This is the core mapping function for the Postgres sink — it gives the user full control over how each Record maps to a database row.
Example:
mapper := func(r types.Record) (string, []string, []any) {
o := r.Parsed.(*Order)
return "orders",
[]string{"order_id", "customer", "amount"},
[]any{o.OrderID, o.Customer, o.Amount}
}
type Serializer ¶
Serializer converts a Record into bytes for writing to an external system. Implementations are plugged into a KafkaSink via the KafkaSinkSerialize option.
If Record.Parsed is non-nil, serializers typically serialize the typed payload. Otherwise they fall back to Record.Value (the raw bytes). The returned bytes become the Kafka message value.
type SerializerFunc ¶
SerializerFunc lets a plain function satisfy the Serializer interface.
type Sink ¶
Sink is where processed data leaves the pipeline. A Sink reads records from the input channel until it's closed or the context is cancelled.
type StdoutSink ¶
type StdoutSink struct{}
StdoutSink prints each record to stdout in a human-readable format. Useful for debugging and examples.
func NewStdoutSink ¶
func NewStdoutSink() *StdoutSink
NewStdoutSink creates a sink that prints records to stdout.
func (*StdoutSink) Describe ¶
func (s *StdoutSink) Describe() SinkInfo
Describe returns metadata for the dashboard.
type TxnKafkaOption ¶ added in v0.4.0
type TxnKafkaOption func(*txnKafkaConfig)
TxnKafkaOption configures a TxnKafkaSink.
func TxnKafkaBrokers ¶ added in v0.4.0
func TxnKafkaBrokers(brokers ...string) TxnKafkaOption
TxnKafkaBrokers sets the Kafka bootstrap brokers.
func TxnKafkaMarkerTopic ¶ added in v0.4.0
func TxnKafkaMarkerTopic(topic string) TxnKafkaOption
TxnKafkaMarkerTopic overrides the transaction-marker topic (default "<topic>.checkpoints"). Should be compacted; deleting it breaks crash recovery of prepared checkpoints.
func TxnKafkaSASL ¶ added in v0.5.0
func TxnKafkaSASL(cfg auth.SASLConfig) TxnKafkaOption
TxnKafkaSASL enables SASL authentication (PLAIN, SCRAM-SHA-256, or SCRAM-SHA-512) for hosted/secured clusters. Applies to both the transactional producer and the recovery marker-probe consumer.
func TxnKafkaSerialize ¶ added in v0.4.0
func TxnKafkaSerialize(s Serializer) TxnKafkaOption
TxnKafkaSerialize sets a serializer applied to record values.
func TxnKafkaTLS ¶ added in v0.5.0
func TxnKafkaTLS(cfg auth.TLSConfig) TxnKafkaOption
TxnKafkaTLS enables TLS. An empty auth.TLSConfig turns TLS on with system root CAs (the common hosted-Kafka case); CAFile/CertFile/ KeyFile configure private CAs and mutual TLS.
func TxnKafkaTopic ¶ added in v0.4.0
func TxnKafkaTopic(topic string) TxnKafkaOption
TxnKafkaTopic sets the output topic.
func TxnKafkaTransactionalID ¶ added in v0.4.0
func TxnKafkaTransactionalID(id string) TxnKafkaOption
TxnKafkaTransactionalID sets the Kafka transactional ID. Required. Must be stable across restarts of the same pipeline (fencing and marker attribution depend on it) and unique per pipeline instance.
type TxnKafkaSink ¶ added in v0.4.0
type TxnKafkaSink struct {
// contains filtered or unexported fields
}
TxnKafkaSink writes records to Kafka inside transactions, one transaction per checkpoint interval, implementing CheckpointedSink for end-to-end exactly-once pipelines:
source offsets + operator state + sink output commit atomically.
Built on franz-go (segmentio/kafka-go has no transactional producer). Every checkpoint transaction also carries a marker record in the marker topic (default "<topic>.checkpoints"); after a crash, the marker's visibility under read_committed proves whether the transaction committed — this resolves prepared-but-unconfirmed checkpoints without Kafka transaction resumption.
IMPORTANT: downstream consumers of the output topic MUST use isolation.level=read_committed, or they will observe records from aborted transactions. Records become visible only when the checkpoint interval's transaction commits — the checkpoint interval is therefore also the output visibility latency.
Usage:
sk := sink.NewTxnKafkaSink(
sink.TxnKafkaBrokers("localhost:9092"),
sink.TxnKafkaTopic("order-summary"),
sink.TxnKafkaTransactionalID("order-pipeline-1"),
)
The transactional ID must be unique per pipeline instance; a second instance with the same ID fences the first (Kafka zombie fencing).
func NewTxnKafkaSink ¶ added in v0.4.0
func NewTxnKafkaSink(opts ...TxnKafkaOption) *TxnKafkaSink
NewTxnKafkaSink creates a transactional Kafka sink. Panics on missing required configuration (broker connection errors surface from Write instead).
func (*TxnKafkaSink) Abort ¶ added in v0.4.0
func (s *TxnKafkaSink) Abort(ctx context.Context, id string) error
Abort implements CheckpointedSink: aborts the transaction for checkpoint id and unblocks Write. During recovery (sink not running) it is a no-op — producer fencing at the next InitProducerID aborts the dangling transaction broker-side.
func (*TxnKafkaSink) Commit ¶ added in v0.4.0
func (s *TxnKafkaSink) Commit(ctx context.Context, id string) error
Commit implements CheckpointedSink: commits the transaction for checkpoint id, opens the next one, and unblocks Write.
func (*TxnKafkaSink) Describe ¶ added in v0.4.0
func (s *TxnKafkaSink) Describe() SinkInfo
Describe returns dashboard metadata.
func (*TxnKafkaSink) SetOnPrepared ¶ added in v0.4.0
func (s *TxnKafkaSink) SetOnPrepared(fn func(id string, err error))
SetOnPrepared implements CheckpointedSink.
func (*TxnKafkaSink) TransactionalID ¶ added in v0.4.0
func (s *TxnKafkaSink) TransactionalID() string
TransactionalID reports the configured transactional ID (recorded in checkpoint files for diagnostics).
func (*TxnKafkaSink) WasCommitted ¶ added in v0.4.0
WasCommitted implements CheckpointedSink: reads the marker topic under read_committed isolation and reports whether checkpoint id's marker is visible — i.e. whether its transaction committed.