Commit Graph
1302 Commits
Author SHA1 Message Date
Wez Furlong a1fb96dfc0 add (low|no)_memory_reduction_policy options
These provide more control over the memory vs spool IO tradeoff
when memory is short.
2025-02-21 10:48:14 -07:00
Wez Furlong 0ab266f95a rocks: add limit_concurrent_(stores|loads|removes) options
Allow enabling a semaphore to specify concurrency constraints
for each of the spool operations.

This can help to avoid spawning hundreds of tokio blocking threads
that will just sit waiting for rocksdb to complete; the main saving
here is memory, as each blocking thread has a larger amount of
stack sitting idle than the per-task memory overhead that waits
for the semaphore.
2025-02-21 09:51:15 -07:00
Wez Furlong 3fc64011eb message: add save_and_shrink_data method
We don't use this anywhere yet
2025-02-21 09:17:27 -07:00
Wez Furlong 3b9d9883cc memory: fixup setting soft limit, add more metrics
expose a count of the number of times we're in a low memory condition as
well.
2025-02-20 17:10:43 -07:00
Wez Furlong 8407ae5d28 kumo-server-memory: fixup warning in cargo doc
These look like html tags that are not closed; quote them
2025-02-20 15:58:52 -07:00
Wez Furlong 7cf6b93783 memory: allow setting soft and low memory limit/thresholds
If you have a lot of RAM, using only default percentages could
potentially leave some RAM unused.  These lua functions
allow more precise control over the limits.
2025-02-20 12:06:12 -07:00
Wez Furlong 1ce8239dd9 add kumo.string.eval_template function 2025-02-20 08:52:04 -07:00
Wez Furlong 9f4a2590c6 templating: expose more of minijinja-contrib 2025-02-20 08:52:04 -07:00
Wez Furlong 45d8449c69 message: add msg:shrink() and msg:shrink_data() methods
These are helpful when explicitly managing memory overheads
2025-02-19 15:55:12 -07:00
Wez Furlong 16dd0f98fc classify: don't run rebinds through bounce classifier
They aren't bounces, so no need to spend the CPU on that effort
2025-02-19 14:43:16 -07:00
Wez Furlong 28e864576e kumod: add env var to control number of worker threads in main runtime
Previously, you could use the standard TOKIO_WORKER_THREADS env
var for this purpose, but since we configure a number of tokio runtimes,
it feels better to split this out into its own separate env var.
2025-02-19 14:14:09 -07:00
Wez Furlong 4d8f03afd4 queue: add faster path for deferred injection insertion
This shaves off some source suspension checks and other locking
overheads that can never apply to the deferred injection queue
2025-02-19 12:52:39 -07:00
Wez Furlong 6907144d1b kumod: rename tokio worker threads
we have more tokio-runtime-w threads showing up than I'd like
to see, this will help to identify where they are coming from.
2025-02-19 12:37:07 -07:00
Wez Furlong bb35ffdb19 ready_queue: add ready queue insertion latency histogram 2025-02-19 12:36:00 -07:00
Wez Furlong d163531c87 refactor: extract guts of readyq_spawn function 2025-02-19 10:06:26 -07:00
Wez Furlong 35e5445944 allow specifying the readyq thread pool for an egress path 2025-02-19 08:57:37 -07:00
Wez Furlong 71098e4944 add kumo.spawn_thread_pool function
This spawns a new Runtime with the specified name and number
of threads.

It is intended to be called from the pre_init event handler.

Nothing else in the code can consume these at this time.
2025-02-19 08:25:51 -07:00
Wez Furlong 35c0166869 server-runtime: adopt parking_lot::Mutex 2025-02-19 08:11:07 -07:00
Wez Furlong a9507438be server-runtime: own name_prefix string 2025-02-19 08:07:57 -07:00
Wez Furlong 01270439f0 server-runtime: extract RuntimeInner 2025-02-19 08:06:48 -07:00
Wez Furlong ede2ac3e65 shaping: downgrade MX resolution error message in provider match 2025-02-13 15:44:44 -07:00
Wez Furlong e6cf0ad74f shaping: skip provider rules for http site names
this avoids logging a spurious but noisy error like this:

kumo_api_types::shaping: Error resolving MX for
http://127.0.0.1:8008.tsa.kumomta: proto error: Malformed label:
http://127. Provider gmail match rules will be ignored
2025-02-13 14:28:56 -07:00
Wez Furlong 8637a2adfe memoize: add len metamethod to MemoizedTable
refs: https://github.com/KumoCorp/kumomta/pull/343
2025-02-12 12:02:26 -07:00
Wez Furlong a2904155fe fix: using commas in display name w/ injection api 2025-02-10 07:39:09 -07:00
Wez Furlong d331df5965 dkim: add separate key cache to signer machinery
The signer cache maps the signer parameters to a pre-made
signing context.

It is essentially a map of (domain, key) -> signer.

Assuming that the (domain,key) tuple is unique, then this is
a good, effective use of that cache.

However, if multiple domains can share the same key then we
can end up re-parsing the same key data for each of them,
which is moderately expensive and a waste of CPU.

This commit introduces an additional cache for the key source to
the resultant compiled key.

This allows sharing of the same compiled key across signing
parameters that otherwise vary, and should help to shave off
some latency.
2025-02-06 16:47:15 -07:00
Wez Furlong 832121e337 dkim: avoid creating unused threads for SIGN_POOL
We only use the blocking threads portion of the thread pool,
so avoid the default of creating number-of-cores threads
for the IO portion.  We have to create one even though we
don't use it, otherwise tokio is unhappy.
2025-02-06 16:47:14 -07:00
Wez Furlong 3d22151d14 add SingletonTimerWheelV2 strategy option
This uses our new leaner timeq data structure; that has lower
memory overhead and is a bit more efficient at ticking.

It is not the default at this time, but ideally will become
the default in the future once it has been proven out.
2025-02-06 13:38:06 -07:00
Wez Furlong 7a12d37b5b roll our own timeq
This one uses our intrusive list so that the memory overhead is
constant, and allows us to iterate the contents, retain() style.
2025-02-06 12:38:08 -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 cf09289579 dkim: allow duration strings to be used for signer ttls
This is a nice convenience
2025-02-05 11:22:46 -07:00
Wez Furlong 833f82a818 egress_source: fix potentially stale rr state when config changes
Previously, we would compare only the names of the pools when
updating the round robin source selection state.

That meant that if you change the composition of a pool by changing
either the number of the definition of its constituent sources,
that change may not take effect until the corresponding queues
had aged out.

This commit resolves this by comparing both the name and the
composition of the pool when deciding to rebuild the source
selection state.
2025-01-29 12:38:38 -07:00
Wez Furlong 8042f7b07a config: invalid pooled lua context when epoch changes
I noticed while testing the throttle serialization commit
that precedes this one that my directly-in-the-lua-file config
changes weren't being picked up when the config epoch changed.

This commit revises the pooling logic to also check the epoch
in addition to the age of the pooled entries.
2025-01-29 11:24:36 -07:00
Wez Furlong 3da38d986e throttle: serialize in string notation
Prior to exposing max_burst in the throttle string parser, we
couldn't guarantee to represent any arbitrary throttle as a string,
so we serialized as the underlying struct fields.

That's a bit unwieldy to read, so let's switch to the string
representation.

This commit makes the string repr infallible (previously it could fail
if you had specified max_burst), then tackles the fanout from that.

Apparently none of our snapshot tests include any of these throttles,
so I manually spot checked it with `kcli inspect-sched-q` to observe
the `max_message_rate`.
2025-01-29 10:57:18 -07:00
ncai a2640800b8 add test for rfc3464 with arrival-date 2025-01-29 10:27:41 -07:00
ncai 1a43079daf convert arrival-date header for oob 2025-01-29 10:27:41 -07:00
Wez Furlong 87e0939f43 throttle: expose max_burst throttle spec
This was always present, it just wasn't something we provided a syntax
to specify.

max_burst allows you to control how quickly your throttle budget will
be consumed over the throttle time period.

The default max_burst is equal to the limit you specify, allowing
the full budget to be instantaneously consumed.

refs: https://github.com/KumoCorp/kumomta/issues/326
2025-01-29 09:22:57 -07:00
Wez Furlong c4d53b07db queue: fix immediately-due requeue race condition
We've been trying to run down an issue where a subset of messages
can get stuck in the scheduled queue. This has only occured in
a single deployment as far as we know; that deployment makes
use of the `requeue_message` event handler.

The identifying characteristics of the bad state are:

* `kcli inspect-sched-q` returns information about messages where
  the due time is less than the `now` field in the inspect result.
* The scheduled queue depth for that queue is flat

I've been scratching my head over this, but I *think* the issue
is a race condition during insertion.  The potential race was:

* [thread a] insert message to SINGLETON_WHEEL that is due immediately
* [wheel maintainer thread] pop due message from SINGLETON_WHEEL
* [wheel maintainer thread] verify that message is tracked by
  queue-local hash <fail>
* [thread a] add message to queue-local hash, bump scheduled queue
  counters

Those immediately due messages would sit there until a rebind forces
them to be reconsidered, or until kumod was restarted (with the same
overall effect).

The race condition could only trigger when:

* The message(s) being inserted are immediately due
* It is some multiple of 3 seconds since the singleton wheel was
  started; that is how often it awakes to process the scheduled
  queue timer wheel.

This commit re-orders things such that the queue-local hash is updated
prior to inserting into SINGLETON_WHEEL. The ordering is enforced
by the containing mutex.
2025-01-28 13:38:49 -07:00
Wez Furlong 8d9b10aad1 rfc5321 client: add Read/Write error variants
We had a few too many "bland" NotConnected errors showing up in
transient failure logs; while it may have been technically
correct, it was lacking in context.

This commit replaces NotConnected in the read/write error paths
with Read/Write error variants that include the error message,
partial read (for Read errors) and the associated command/stage.

For pipelining errors, we can now dup this same state into each
of the command slots when considering the pipelining error as
well; previously we couldn't clone the error type because of
the (unused!) ssl error variant.
2025-01-28 13:16:44 -07:00
Wez Furlong 9f8602bd1d maildir: handle TOCTOU-ish race when creating dir structure
The CI flakes I've been running down are due to this:

```json
{"type":"TransientFailure","queue":"maildir","response":{"code":400,"enhanced_code":null,
"content":"failed to write to maildir: creating dirs for maildir /tmp/.tmpBi1p8H/maildir in queue maildir: File exists (os error 17)"}
```

which sounds like a race condition when multiple threads are trying
to create that maildir directory structure from scratch at the same
time.

This commit adds some error handling to catch and deal with this
appropriately.
2025-01-28 12:34:21 -07:00
Wez Furlong 00241b85cc ci: reduce flakeyness of disconnect/reconnect strategy tests
Make sure that we wait for the sink deliveries to complete before
making the overall summary assertion.
2025-01-28 11:19:54 -07:00
Wez Furlong 3af505f450 kcli: tracer: allow unbounded buffering of trace data
It's more acceptable for the client to go nuts with its own memory usage
than it is for the server side to waste memory on trace data, so let's
allow it to buffer indefinitely while it is busy formatting the output.
2025-01-28 11:07:59 -07:00
Wez Furlong dc1541c030 kcli: tracer: remove redundant bytes read|written output
When we output just a single line of data, there is no need
to also emit another line with its length. This was a side effect
of adding terse mode to the client side.

Now that we're doing the terse processing server side, the
non-Abbreviated cases are never actually terse-processing eligible
on the client (assuming that the client and server version match),
so having the byte length summary presented there is especially
noticeable.

We can simply elide it by trimming off trailing whitespace.
2025-01-28 10:59:09 -07:00
Wez Furlong 5f76d85d23 kcli: switch tracers to async websocket client
This should make things play a little more nicely in the client,
but it's not a significant difference in throughput or performance.
2025-01-28 10:49:23 -07:00
Wez Furlong d224feb62f tracing: enable server-side processing of terse flag
Cutting down on the data being transmitted can reduce the number
of lag events.

Increase the channel buffer size as well while we're in here.
2025-01-28 10:35:19 -07:00
Wez Furlong e3c3f5fbe0 tracing: emit diagnostic if the tracer has lagged
Previously we'd simply drop the connection. With this behavior we now
emit an error to the journal (once per tracer session) and emit a
diagnost to the client (each time) whenever some number of events
were dropped by the internal broadcast channel.
2025-01-28 10:35:19 -07:00
Wez Furlong 33bc16555b smtp_dispatcher: add message_id to tracer metadata 2025-01-28 10:35:18 -07:00
Wez Furlong dccb0cc03a smtp_dispatcher: respect reconnect_strategy for 503 errors 2025-01-28 10:35:18 -07:00
Nathalie Caiandncai 1dc4081c1d change kafka payload type to vector of bytes (#328)
* change kafka payload type

Co-authored-by: ncai <ncai@chapsvision.com>
2025-01-28 10:35:04 -07:00
Wez Furlong a17971e4c3 ci: increase some timeouts
This reduces flakiness when there are multiple jobs running concurrently
in CI
2025-01-27 09:51:36 -07:00
Wez Furlong 768181ac2b smtp_dispatcher: avoid categorizing reconnects as "no more hosts"
This adds a way for the lower level dispatcher impl to communicate
back up to the higher level that the session is done and can be
closed out without treating it as a connection failure.

For SMTP the criteria for this is that, if we ever got as far
as MAIL FROM, then we consider that the connection was established
OK and that means that if we subsequently reach a point where we need to
connect again, then it must be due to an earlier policy issue that was
already recorded as a transient failure.

In that circumstance, if we have not more hosts to connect to, we
will indicate that we terminated "OK".

This works because the upper level checks for this state before
asking the session to connect again.

If there are more addresses that could be tried, we will report a
connection failure for the next message picked up by the session;
this commit only changes the behavior for the case where there
are no more addresses left in the current connection plan.
2025-01-27 09:01:37 -07:00