Commit Graph
54 Commits
Author SHA1 Message Date
Harsh JhaandWez Furlong 00f3131f7d Allow configuring which records TSA skips
Closes: https://github.com/KumoCorp/kumomta/pull/525

Co-authored-by: Wez Furlong <wez@wezfurlong.org>
2026-05-29 15:02:31 +01:00
Wez Furlong 11e952fa98 shaping.lua: stylua format 2026-02-20 08:08:38 +00:00
Wez Furlong 26135a2b53 filter out not-relevant-to-TSA events earlier in the logging
I believe this to be more of a micro optimization, because the
heavy lifting was already being done in the should_enq function,
which filters out before we commit the event to the spool.

Thanks to @smsvip for noticing that there was a discrepancy
between the UNINTERESTING_LOG_RECORD_TYPES and the per-record
configuration; we now use the former to derive the latter.

I've add more obviously irrelevant to TSA types to the config
as part of this commit.

refs: https://github.com/KumoCorp/kumomta/pull/481
refs: https://github.com/KumoCorp/kumomta/issues/478
2026-02-18 15:05:18 +00:00
Wez Furlong f92df0fca0 lruttl: introduce allow_stale_reads option
This is paired with a corresponding field in the memoize options
struct, which is in turn exposed to the shaping helper shaping_data
cache via the `allow_stale_shaping_data` field.

The effect of setting this to true is:

* Undoes the effect of invalidate_with_epoch, as stale reads cannot
  be epoch based
* If a semaphore wait times out, and a stale value was present in
  the cache, that stale value will be returned to the caller

To facilitate this behavior, the lruttl cache introduces a new
state for a cached value: `Refreshing`, which is a combination
of both `Present` and `Pending`.

When stale reads are allowed, we take care to avoid unilaterally
replacing `Present` with `Pending` when an item has expired.

Whenever we satisfy a lookup with a stale value, we will bump a new
lruttl_stale_count counter for that cache.  Previously, we would
classify those as errors.

Something else that changed as part of this commit, is that we now set
an overall deadline for the semaphore wait operation; previously, each
wait would allow for up to the specified semaphore timeout, but now the
total wait time for that lookup will be bounded to the specified
timeout.
2025-04-30 14:01:26 -07:00
Wez Furlong 95654c61fd shaping.lua: increase shaping_data cache capacity
I've observed a system where we had more than 4 outstanding
shaping_data lookups from different ConfigEpochs; that system
had slow dns resolution and we ended up looping for these because
the capacity was not high enough and the population of the result
always took too long.

Let's just give ourselves a bit more headroom; this coupled
with the earlier commits that adjust retry behavior should
help to smooth things out in this situation.
2025-04-06 09:55:02 -07:00
Wez Furlong c9ab140ac1 shaping.lua: expose memoize populate retry/timeout params
undocumented for the moment
2025-03-21 16:59:13 -07:00
Wez Furlong 9b065fb133 shaping.lua: revise update strategy for tsa pushed data
Previously, we'd build a little map of existing rules and check
things off against it, but that doesn't have the best scaling
properties, because we need to copy the full set of bounces/suspensions
into lua and check against that.

Since the underlying bounce/suspension tracking stuff already
guarantees that inserting a record with the same criteria will
replace another, this checking in lua-space was redundant and
wasteful, so we can just remove it.

This commit also adds some debug logging to show how many
records are being processed.
2025-03-18 14:05:53 -07:00
Wez Furlong 98e99594d9 shaping: process tsa websocket pushes in batches
We'll wait up to 3s at a time for however many mesages are available
to extract from the tsa daemon websocket, then process the results
in batches.

This avoids the potential for geometric complexity if there is a run of
subscription updates happening around the same time.
2025-03-18 14:05:30 -07:00
Wez Furlong 9e6321ecb6 shaping: add timeout for tsa shaping data fetches 2025-03-18 14:05:30 -07:00
Wez Furlong 5b3d94ef98 lruttl: potentially squash sema/eviction errors from logs
A couple of users have reported seeing:

  sema was closed but state is still pending

and/or

  lruttl: shaping_data did not find anything to evict, target was 1

messages in the diagnostic logs.

These arise due to the capacity of 1 that was configured
for the shaping data cache in the shaping helper and a race
condition where lookups are interleaved around a config epoch
bump triggered either by the initial epoch bump on startup,
or a bump produced by the TSA daemon.

This commit adjust the strategy for handling those errors if/when
they arise by attempting to restart the cache lookup process.

In addition, this commit raises the capacity of the shaping data
cache to avoid this point of contention.
2025-03-15 09:58:53 -07:00
Wez Furlong f23875b1a1 shaping.lua: mostly switch prints to kumo.log_XXX
Keeping the validation stuff as prints for the time being,
as I think that looks nicer in the context of a standalone
validation mode.
2025-03-07 08:06:35 -07:00
Wez Furlong 5c154417c7 shaping.lua: fix missing string.format calls
closes: https://github.com/KumoCorp/kumomta/issues/351
2025-03-04 16:24:58 -07:00
Wez Furlong 0666374f58 tsa: expose underlying log hook back_pressure to configuration 2025-02-24 08:59:58 -07:00
Wez Furlong a805184a8f remove deprecated unused fields from tsa shaping object 2025-02-24 08:59:24 -07:00
Wez Furlong 161e7b6d3b shaping.lua: ignore Rebind and Delayed log record types
Cut out rebind and delayed log records from the feed to the TSA
daemons.  These don't make sense to have TSA rules applied to
them, and in some configurations (such as deferred injection)
these records can 2x the volume of records being processed.

With pre-filtering enabled those records won't make it to the TSA
daemon, but we would still need to run those records through the
rules to realize that.

With this commit we can cut these out in O(1) and minimize the
local CPU cost of that.
2025-02-24 08:31:46 -07:00
Wez Furlong 0ab606cfee memoize: make epoch-based invalidation optional
It is not always desirable to invalidate with the epoch,
so allow opting in instead of always invalidating that way.
2025-02-06 11:06:25 -07:00
Wez Furlong b3aa6d4154 shaping.lua: explicit gc in kumo.tsa.config.monitor
The config monitor task is a long-lived task that runs
inside the same lua context for its entire lifetime.

That task obtains a reference to the current shaping data
every 30 seconds to decide whether it needs to synthesize
an update to the config epoch.

Lua's memory management cannot see the total amount of
ram consumed by the shaping data because the shaping data
is a userdata type whose ram is managed externally.
That means that lua things that this task is generally not
using many resources (~ a handful of pointers per loop iteration)
and gc doesn't kick in very aggressively.

For sites with large TSA shaping overrides, or otherwise with
very large shaping data, this can result in an accumulation
of stale shaping data in that long-lived lua context.

This commit adds an explicit gc trigger before the task
sleeps on each iteration so that we can release those references.
2024-12-13 06:38:34 -07:00
Wez Furlong db7d846e3a shaping.lua: reduce memoize cache capacity to 1
Since we produce one large Shaping object from the static set
of inputs (eg: the list of files), there isn't a lot of benefit
from caching the prior 9 generations of the shaping config.

Some sites have especially large sets of TSA-produced shaping
overrides which can add to memory pressure.
2024-12-10 09:09:06 -07:00
Wez Furlong 6da455d42b kumod: process TSA Bounce rules and apply as bounces
Accepts scheduled queue bounce events from the event subscription,
and translates them into local admin bounce records.

refs: https://github.com/KumoCorp/kumomta/issues/272
2024-12-09 07:15:45 -07:00
Wez Furlong a316f7a9c4 shaping.lua: use new tsa endpoint, falling back to old
Adjust our subscription to try the new generic event endpoint,
and if that 404's, fall back to the suspension endpoint.

This commit doesn't add support for the new bounce records,
it is focused on ensuring that suspension information is
returned correctly for both old and new endpoints.

The integration tests will use the new endpoint only
because it is too much of a faff to run them against
a legacy tsa-daemon (since we can only build and run
the current one here).

I tested this commit in phases though:

* Deliberately used the wrong URL for the new endpoint to
  trigger the 404 logic case and handle fallback
* Inserted an error in the fallback case to ensure that
  the fallback wasn't happening once the new endpoint URL
  was set to the correct one.

So this should enable folks to upgrade either TSA or kumod
in either order across their deployment, without the "mismatch"
in TSA and kumod versions harming their traffic.

refs: https://github.com/KumoCorp/kumomta/issues/272
2024-12-09 06:22:32 -07:00
Wez Furlong d31c0f2dfc shaping: allow granular control of how checks are reported
At the lower level, expose an options struct that allows control
over how various checks and conditions are reported out of the
attempt to load the set of shaping files.

Expose a separate list of errors, distinct from warnings.

Each check can either be ignored, a warning, or an error.

Errors cause validate-shaping and --validate mode to exit
with an error condition, whilst warnings are simply emitted
as informational items.

In the shaping helper, it is possible to configure a separate set of
options for the main live service and validation mode, which allows you
to run a more relaxed configuration by default, but be a bit more strict
in your pre-commit and pre-deploy configuration validation pipeline

refs: https://github.com/KumoCorp/kumomta/issues/287
2024-10-02 10:12:42 -07:00
Wez Furlong 6842843644 shaping: enable Epoch refreshes with TSA
This commit introduces a background task that will periodically (every
30 seconds) fetch the shaping data, uncached.  If the hash of the
shaping data has changed since the last run, it will bump the current
config epoch.

Combined with setting the refresh strategy to Epoch, this will
cause the ready queue config maintainer to wake up and refresh
all the egress path configs.

This commit reduces the latency for detecting TSA config updates
and also the overhead of applying those changes to the various
ready queues.
2024-09-02 10:42:14 -07:00
Wez Furlong baefa4651f ready_queue: add epoch and refresh_interval options to path config
This commit changes the config refresh strategy for ready queues
to be similar to that of scheduled queues; there is now a per-queue
refresh_interval possible, as well as the ability to select Epoch
based refreshes.

Shaping will use Epoch when TSA is not in use; a future commit
will enable Epoch for TSA.
2024-09-02 10:42:14 -07:00
Wez Furlong bf3d8d45f7 tsa: default pre_filter to enabled
Graduate this to default to enabled; it's generally the right
trade.
2024-08-20 07:28:12 -07:00
Wez Furlong e3d7aef982 shaping.lua: fix --validate'ion issue
We can't lazily require the sources helper from inside an
event handler, as that may trigger a runtime error that
tells you that you shouldn't define an event handler
from code running in an event handler.
2024-08-13 18:19:27 -07:00
Wez Furlong 3b61f1b92c shaping.lua: pre-match log records against shaping rules
Rather than queueing up a complete copy of all logs to send
to the TSA daemon, we now perform a match on the client side.
If the record doesn't match any rules then we won't bother
sending it to the daemon.

Otherwise, we'll queue and send.

This reduces the amount of data that we'd need to queue, thus
reducing IO pressure, and reducing inter-node bandwidth.

This new behavior is currently opt-in, but will likely
be the default by the time we cut the next release.

To opt-in, add `pre_filter = true` to the `setup_with_automation`
parameters.
2024-08-09 07:28:17 -07:00
Wez Furlong 3139be2cfd Add new kumod --validate flag
The purpose is to provide a deeper, offline validation pass
of the policy configuration, prior to deploying and making it
live.

The system behavior changes when in `--validate` mode:

* Listeners, spool and spawned tasks will be silently skipped;
  the parameters will be validated but the primary functions
  of those things will be skipped silently.
* After triggering the `init` event, an additional new `validate_config`
  event (which can be registered multiple times) will be triggered
  to allow lua modules to perform extended validation.
* A module can either raise an error via `error` to immediately report
  a problem, or instead call a new, preferred, `kumo.validation_failed()`
  function to flag validation as failed but allow additional validation
  to be performed and summarized all together.
* Once the `validate_config` event returns, the process will terminate
  with either exit code 0 for a successful validation, or non-zero
  to indicate that something failed.

Validation errors are reported in a human readable form.

This commit adds validate_config event handlers for the following
helper modules:

* `shaping` - any warnings reported by the underlying rust code
  will be reported here and cause validation to fail. This is
  functionally equivalent to using the `validate-shaping` binary,
  except that it will automatically be passed the set of shaping
  files defined by your `init.lua`

  If the `sources` helper is also configured, the list of sources
  referenced by the shaping config will be cross-checked against
  the sources data to confirm that all possible sources are defined.

* `sources` - each listed source and pool will be validated by
  calling `kumo.make_egress_source` or `kumo.make_egress_pool`
  respectively.

  Pool membership will be validated to confirm that every
  listed pool is defined in the sources data.

* `queues` - each domain and tenant that references an egress_pool
  will be cross-checked with the `sources` helper, if the sources
  helper has been configured.

It is now an error to attempt to setup any of the above helpers
more than once.

refs: https://github.com/KumoCorp/kumomta/issues/211
2024-06-25 11:05:04 -07:00
Wez Furlong b4aa4a38ec http: allow controlling some timeout and diagnostics on the client
Adds a couple of options that provide more control over the default
timeouts and logging.

These are exposed to the shaping helper as `publish_timeout`,
`publish_pool_idle_timeout` and `publish_connection_verbose`.
2024-04-19 07:44:19 -07:00
Wez Furlong 415d4fc19c tsa: make the default queue config for tsa-daemon more aggressive
while troubleshooting a situation where the
http://127.0.0.1:8008.tsa.kumomta queue is backing up, I noticed that
we're using the default queue configuration for this queue.

Let's make it more inline with the defaults for webhooks; give it a
1 minute base retry with a 20 minute max.

These parameters are configurable; you can pass in `tsa_queue_config` to
the setup_with_automation call to specify your preferred values for the
scheduled queue config.
2024-04-10 14:17:23 -07:00
Wez Furlong e94506fd96 Add new Rejection log event
We skip logging the 421 we generate while shutting down because
it feels a bit redundant; you'll see the server shutting down
in the journal anyway.

refs: https://github.com/KumoCorp/kumomta/issues/88
2024-03-29 16:37:37 -07:00
Wez Furlong 0c5794ba31 TSA: Add SuspendTenant, SuspendCampaign
refs: https://github.com/KumoCorp/kumomta/issues/113
2024-03-28 13:08:45 -07:00
Wez Furlong e41b4297ea tsa: hook up websocket suspension stream
This commit connects the new websocket based suspension feed
up to shaping.lua. This allows ready-q suspensions to be
enacted in realtime, as well as sets things up to support
scheduled queue suspensions in a later commit.

refs: https://github.com/KumoCorp/kumomta/issues/113
2024-03-28 07:14:36 -07:00
ncai 9d0105e51d use logRecord reception_protocol to avoid loop 2023-11-07 13:11:59 -07:00
Wez Furlong 48d5e26a70 pre_init: fix dispatch
I didn't register this correct for multi-event setup,
so no pre_init event was ever triggered, causing the log_hooks
stuff to not register the log hook.
2023-11-06 20:55:37 -07:00
Wez Furlong d969f87571 multi hooks: use bare return rather than return nil
The way we test whether logs should continue is by looking for
an empty return statement, so we shouldn't `return nil` for these
otherwise we'll indicate that we definitively can't resolve the
queue configuration.
2023-11-06 14:39:37 -07:00
Wez Furlong 1c25c0a59b shaping.lua: add extra_files to the TSA inline example 2023-11-06 08:53:34 -07:00
Wez Furlong 1872dc71a0 shaping: calling shaper.should_enqueue_log_record is no longer required
Allow multiple should_enqueue_log_record hooks to be registered,
and take advantage of that inside the shaping helper.

`shaper.should_enqueue_log_record` no longer needs to be explicitly
plumbed from the config, but we allow calling it still for compatibility
reasons.

We will remove that compatibility after the next stable release.
2023-11-03 08:52:40 -07:00
Wez Furlong 3d7007825a shaping: calling shaper.get_queue_config is no longer required
Take advantage of the ability to define multiple get_queue_config
callbacks by internalizing the TSA webhook queue configuration.

`shaper.get_queue_config` no longer needs to be called, and
that fragment of code will continue to "work" by simply not
having an effect so that we don't break folks on upgrade.

We'll remove this compatibility in the release following
the next stable release.
2023-11-02 18:11:17 -07:00
Wez Furlong 39a046e07c docs: add missing routing_domain param to get_queue_config event examples 2023-10-18 06:56:01 -07:00
Wez Furlong c8a040dfc4 tsa: teach shaping.lua to pull from the tsa-daemon
Refine the egress path update logic as part of that, so that we wake
sleeping Dispatchers to have them notice when it changes.
2023-08-03 11:36:02 -07:00
Wez Furlong a327e3db0c ready_queue: periodically refresh path_config
To facilitate more dynamically updating the configuration, this commit:

* Introduces a ConfigHandle type to aid in building shared configuration
  objects that don't require full mutex interlock
* Switches ReadyQueue and Dispatcher to hold egress path config in a ConfigHandle
* ReadyQueue maintainer will now refresh, by calling
  get_egress_path_config, the value in the config handle
* shaping.lua now uses a ttl of 1 minute (which is the same as the
  ReadyQueue maintainer interval), so that the ready queues should
  reflect egress path configuration changes approximately every minute.
2023-08-03 08:20:40 -07:00
Wez Furlong 22b5f43f84 shaping.lua: fix typo 2023-08-02 09:10:01 -07:00
Wez Furlong 16ea223ae8 tsa: basic rule matching
This is plumbing to perform rule matching.
It doesn't do anything useful with matches yet.
2023-08-01 13:58:50 -07:00
Wez Furlong 45e1564459 shaping: use the rust parser in shaping.lua 2023-07-31 16:57:15 -07:00
Wez Furlong 270c72cd83 tsa-daemon can now ingest log records
Using the init_with_tsa.lua policy for kumod, together with
tsa_init.lua as the policy for tsa-daemon, logs from kumod
are now sent to tsa-daemon.

It doesn't do anything with them yet.
2023-07-31 16:57:15 -07:00
Wez Furlong b00d8a44db shaping: more prep for automation 2023-07-31 16:57:15 -07:00
Wez Furlong d2d6965d11 shaping: refactor in preparation for automation
Introduce a setup_with_automation entrypoint that will accept
a richer parameter struct to specify the shaping automation
daemon(s) to which to push logs and from which we will pull
configuration.

This is just a refactor: none of that stuff is done yet.
2023-07-31 16:57:15 -07:00
Wez Furlong fb1df13447 shaping.lua: make DNS resolution errors non-blocking
We'll just ignore the associated rules instead.

refs: #57
2023-06-16 07:49:15 -07:00
Wez Furlong 628cda23ce shaping.lua: table_keys lives in utils 2023-06-12 16:07:47 -07:00
Wez Furlong 9708bbb1de fix more typos 2023-05-31 12:44:46 -07:00