Skip to content

Signature formatters are rebuilt for every destination #1022

Description

@alexluong

CreatePublisher builds both signature template formatters per destination:

WithSignatureFormatter(NewSignatureFormatter(d.signatureContentTemplate)),
WithHeaderFormatter(NewHeaderFormatter(d.signatureHeaderTemplate)),

Both template strings are provider fields — the same value for every destination. Each constructor calls sprig.TxtFuncMap(), building a map of ~200 functions that the parsed template then retains. Every cached publisher ends up holding private copies of two identical function maps.

Built unconditionally, including for destinations with signatures disabled.

Cost

Measured on an M1 Pro. Per formatter, to build: ~50 µs, ~53 KB, 50–70 allocs. Retained heap, measured after GC across 2,000 publishers' worth of formatters: 43.6 KB per cached publisher.

cached destinations retained
100 ~4 MB
1,000 ~44 MB
10,000 (publisher cache cap) ~436 MB

Noise at a few hundred destinations. At the cache ceiling it's likely the single largest consumer.

Proposed change

Build the formatters once in the provider's New(), replacing the stored template strings:

// today
signatureContentTemplate string
signatureHeaderTemplate  string

// instead
signatureFormatter SignatureFormatter
headerFormatter    HeaderFormatter

CreatePublisher passes them through, leaving secrets as the only genuinely per-destination input:

sm := NewSignatureManager(
	secrets,
	WithSignatureFormatter(d.signatureFormatter),
	WithHeaderFormatter(d.headerFormatter),
	WithEncoder(d.encoder),
	WithAlgorithm(d.algorithm),
)

Sharing is safe: both formatters hold a single *template.Template and Format executes into a local buffer, and text/template is documented safe for parallel execution once parsed. No synchronization needed.

GetEncoder and GetAlgorithm are worth hoisting in the same pass — both stateless, both derived from provider config.

destwebhookstandard has the same shape and needs the same treatment.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    destinationRelates to destinations supportenhancementNew feature or requestsmallLess then a day of work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions