Commit Graph
3078 Commits
Author SHA1 Message Date
Wez Furlong dd57bcfabe kumod: add kumo-api-types to default log filter
This is mostly to aid in my debugging efforts
2025-04-10 14:30:56 -07:00
Wez Furlong 06fa510510 kumo.spawn_task: move away from LocalSet
This is lingering from the past; we don't need LocalSet any
more. I thought this might be causing some scheduling issues,
but it was neutral overall, so this commit is really just
a code cleanup.
2025-04-10 14:29:49 -07:00
Wez Furlong 5080fdbca5 tsa: improve error messaging around sqlite busy result
Show when things are taking a while, and clarify the
timeout value that was hit when/if we experience
SQLITE_BUSY.
2025-04-10 12:24:14 -07:00
Wez Furlong 76e73084f8 tsa: minor refactor: better encapsulate database 2025-04-10 12:04:41 -07:00
Wez Furlong f8ccda9dfc admin bounce: add caching+negative caching for queue insertion
For sites with large numbers of admin bounce entries, it is
desirable to negatively cache the lookup so that we can avoid
extraneous matching overhead.

We use a generation counter to determine if any rules have changed
and allow that to drive the invalidation of negative caching.

Otherwise, we cache the last lookup and, if the generation is the
same, then we cache the prior result and respect its expiration.
2025-04-10 10:37:57 -07:00
Wez Furlong 81b840b317 cargo update 2025-04-10 08:44:39 -07:00
Wez Furlong 8ecbe25b4e set_timeq_spawn_reinsertion is now the default
After running this at a couple of sites, this appears to be
good overall, so let's remove the option, reduce complexity
and make things better by default.
2025-04-10 08:42:18 -07:00
Wez Furlong 95ed7cfdc3 singleton wheel: shift admin bounce detection to insert_ready
I noticed on a busy system with over 1500 active admin bounce
entries (created via automation) that cpu was quite busy in qmaint.

I believe that is because we were potentially spawning a new
async qmaint task for every message moving from the wheel and into
the ready queue.

This commit removes that logic, and replaces it with a per-message
check in insert_ready.
2025-04-10 08:32:54 -07:00
Wez Furlong cc2383af80 log hooks: release backlog sema prior to insertion
Queue insertion can generate log records if queues are full,
so holding a backlog permit could lead to blocking-like
behavior when the system is relatively saturated.

Let's release the permit prior to insertion; that way
it still provides some benefit (limiting the should-enq hook
calls) while not getting in the way.
2025-04-09 10:46:22 -07:00
Wez Furlong 4307849e5b lruttl: simplify with more defer!
Replace my manual Drop helper with a defer! block
2025-04-09 10:46:15 -07:00
Wez Furlong e26ac46535 add some clippy rules for dashmap
They didn't catch anything, but we have them in place for the
future.
2025-04-09 10:26:12 -07:00
Wez Furlong 4b7577ebbd even more clippy 2025-04-09 10:26:12 -07:00
Wez Furlong a1f4172f4f more clippy 2025-04-09 10:26:12 -07:00
Wez Furlong dc265804d3 summarize-memory: clippy suggestion 2025-04-09 10:26:11 -07:00
Wez Furlong e3fdcaa628 cargo clippy --fix 2025-04-09 10:26:07 -07:00
Wez Furlong d6a376f2f3 cargo update 2025-04-08 12:44:54 -07:00
Wez Furlong 89d1398b17 lruttl: improve cancellation safety
The pattern used in the logic was that in the Pending case,
once we had acquired the semaphore, we'd do some prep work,
then await the completion of the populator function, then
store the result and then close the semaphore to force all
wakers to kick out and consult the return value.

The await is a cancellation point, which means that if the
call stack above the population function encounters a timeout
(eg: data_processing_timeout) then the whole state is dropped
and never consulted again.

The drop would release the semaphore permit and allow another
actor to acquire it, which is partially OK, but we really do
want to close the semaphore to wake up everyone in that case.

This commit switches from the explicit close at the end of
the scope to using defer! to handle it in all exits from
that particular scope, including the drop on cancellation.

Doing that highlighted a busy loop in response to the cancellation; to
deal with that, while we have the entry locked, if the semaphore is
already closed we'll treat it the same way as an expired ttl and allow
kicking off a new resolve.
2025-04-08 12:44:41 -07:00
Wez Furlong 1cc4027acf egress_source: add negative caching for queue names
This is a micro optimization, but it helps to take a little
bit off pressure during queue name resolution if the domain
isn't resolving.
2025-04-08 12:44:41 -07:00
Mike Hillyer b034b1b9df Update bounces.toml
Adding a couple of missed codes.
2025-04-07 22:21:22 -04:00
Wez Furlong 0f6491b6b1 ci: amazon: pull the base amazon image
The issue was that there was a major update to libstdc++; that's
visible in our builder image, but our CI system had the older one
cached.

Probably.
2025-04-07 07:12:36 -07:00
Wez Furlong f741fa786a ci: speculative fix for amazonlinux2023 build issue
yum doesn't think that anything has libstdc++, it's probably
a metadata issue in that image.
2025-04-07 06:46:56 -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 d5e3d6a82a lruttl/memoize: adjust retry behavior
It's not a good idea to automatically retry internally at the lruttl
layer, as there is no bound on the retries and not enough context in the
cache layer to decide if we really should retry.

This commit removes the `retry_on_sema_timeout` flag from lruttl
and replaces the implementation of the mod-memoize
retry_on_populate_timeout flag with a simple 3 attempt retry
loop in the failure case.

Importantly, those retries in mod-memoize have the opportunity
to adjust to a bumped ConfigEpoch, which is important for the
pathological situation where a flood of changes stream in from
TSA daemon and there is a delay in handling populate, and the
cache capacity is not sufficient to accommodate that run
of epoch bumps.
2025-04-06 09:49:19 -07:00
Wez Furlong 8b1b639d98 message: implicitly load data/meta when calling lua get/set meta/data
I saw an instance where the throttle_insert_ready_queue event was
trying to inspect the metadata but failing because the metadata was
not loaded.

This should avoid that problem.
2025-04-06 08:59:44 -07:00
Wez Furlong eda083f083 dns-resolver: use thundering herd protection and add semaphore
This commit does two things:

* Migrate the limit of 128 concurrent lookups from the shaping code
  and into the general mx lookup code
* Adjust the mx lookup implementation to run inside the cache
  getter, which applies thundering herd protection to the lookup.

These together will constrain the amount of queries being sent
to the upstream dns resolver and reduce the chances of it being
overwhelmed, especially if we are doing duplicate queries from
multiple concurrent contexts simultaneously.
2025-04-06 08:45:49 -07:00
Wez Furlong 5eb57e63d5 shaping.toml: disable dane for office365-dane
We cannot default it to enabled because a fully working
dane setup requires additional configuration in the resolver
and we cannot guarantee that that has happened here.
2025-04-06 07:47:00 -07:00
Wez Furlong f940ce6b72 Show version info on service startup
It's a little awkward to reason about whether you're running the latest
build or not after an upgrade, so let's explicitly print the version
to the journal.

For posterity, regardless of whether you have this particular commit or
not, you can determine the running/online version by looking at the
openapi schema document:

curl -s 'http://127.0.0.1:8000/api-docs/openapi.json' | jq .info.version
2025-04-05 07:02:22 -07:00
Wez Furlong 2b1146aa91 queue: avoid potential "singleton_wheel: reinsert_ready: metadata must be loaded first"
There is a potential race between the timerwheel tick and bulk queue
operations (flushing, bouncing).  The logic in the tick case has
some accommodations for this, but there is another outstanding
that can result in racing to manage the metadata load state
on a message.

In the tick case, we load it if needed, then resolve the queue
name, so that we can resolve the Queue handle.

We need the queue handle to decide whether we are responsible
for the message, or whether we might be racing with a concurrent
action.

In the race case, the other actor may have decided to release
the message metadata, which will cause the queue name resolution
to fail.

While we could just shrug and silently ignore the error in that
case, that makes me uneasy.

What this commit does is adjust the v1 wheel entry so that we
capture weak references to both the message and its containing
queue.

Then when we tick, we can simply upgrade both of those and
reconcile without needing to manipulate any message metadata.

These changes unfortunately result in re-duplication of some
of the logic that I recently refactored to be shared with the
v2 tick implementation.

The v2 tick implementation has the same edge case around
metadata, but cannot be easily adjusted to use the same
pattern.

So this commit sticks a comment in the code; nobody is using
v2 AFAIK, and there have been reports of some wonky behavior
with it.  My recommendation at this time is to avoid using
the v2 wheel and we can fix this all up for it later.
2025-04-04 15:52:17 -07:00
Wez Furlong a24ff89bd1 add some more error context to a couple of stack traces 2025-04-04 14:48:14 -07:00
Wez Furlong 3995e62a33 message: disambiguate "metadata must be loaded first" errors
We have a couple of different places that might emit it,
let's annotate each one so that we know where it might
be coming from.
2025-04-04 14:40:19 -07:00
Wez Furlong dce5dd3082 deps: update openssl 2025-04-04 13:58:40 -07:00
Wez Furlong d96758bc6d cargo update 2025-04-04 13:53:27 -07:00
Wez Furlong e7ca5b4424 docs: update changelog to reflect more of kcli top's new features 2025-04-04 13:51:34 -07:00
Wez Furlong 129dbac461 kcli/top: support fuzzy matching series and heatmap names
Press f to edit the filter, watch it fuzzy match as you type.
2025-04-04 13:49:44 -07:00
Wez Furlong a9a096e76b kcli/top: refactor keyboard input
Move processing into state; this will aid in a future commit.
2025-04-04 10:32:07 -07:00
Wez Furlong bb9d786c86 kcli/top: scroll to tab when switching tabs 2025-04-04 08:14:04 -07:00
Wez Furlong f3a84fd40f kci/top: shift most heatmap math to accumulator stage
No need to rebuild/recompute the full data on each render
2025-04-04 08:11:12 -07:00
Wez Furlong 319b83bf8f kcli top: improve avg/freq labels
Some of the series ended up with bland labels like "lua" with
no context.  Let's include the overall metric name for those.

The consequence of this is that the labels column gets wider,
but I think that now that we have scrolling, we can adjust
that presentation in a follow up commit.
2025-04-04 07:59:46 -07:00
Wez Furlong 04ea7e5804 kcli top: auto add all histograms 2025-04-04 07:49:50 -07:00
Wez Furlong cb1c87ab15 kcli top: initial support for showing heatmaps 2025-04-04 07:17:05 -07:00
Wez Furlong ad7e98e7c5 kcli top: add basic help tab 2025-04-03 14:57:51 -07:00
Wez Furlong 4f8aadb05a kcli top: +/- increase/decrease the "zoom" of each row 2025-04-03 14:19:29 -07:00
Wez Furlong 0fc21cbbc6 kcli top: add vertical scrollbar
There are a lot of metrics these days, we need to scroll through them!
Use the arrow keys, page up/down and home/end for this purpose.

closes: https://github.com/KumoCorp/kumomta/issues/372
2025-04-03 14:00:59 -07:00
Wez Furlong 5e6e2c9497 kcli: update ratatui dep 2025-04-03 14:00:59 -07:00
Wez Furlong 3d0d0ebce1 kcli: refactor: split into more modules
no functional change
2025-04-03 12:48:57 -07:00
Wez Furlong c7fe9489c3 fix: failure to load ed25519 dkim private key
This was probably the casualty of some earlier refactoring
that has gone unnoticed until now.

Since we don't have explicit context on which key format to
parse in this helper function that is used in multiple places,
let's just make it try to parse both rsa and ed25519.

closes: #368
2025-04-03 10:11:24 -07:00
Edgar Vaitkevicius d0314c0f3a Updated Kafka producer docs
They mistakenly referred to AMQP and queues before.
2025-04-03 09:37:04 -07:00
Wez Furlong 7b9732d452 docs: mention systemd environment files in changelog 2025-04-03 07:35:02 -07:00
Wez Furlong f8bbacba54 systemd: read optional environment files
It is sometimes necessary to set environment variables
to adjust some early-startup options that need to be
applied before enough of the system is ready to read
lua policy files.

While it is possible to use `systemctl edit SERVICE`
and enter systemd-specific directives to configure that,
it is not the most convenient thing.

What this commit does is introduce 3 new optional files:

* /opt/kumomta/etc/kumo-common.env: sourced by kumod and tsa
* /opt/kumomta/etc/tsa-daemon.env: sourced by tsa
* /opt/kumomta/etc/kumod.env: sourced by kumod

The format of these files is `NAME=VALUE` on each line, as
per the `EnvironmentFile` docs in systemd.

One practical application for this is on an over-committed system
where the number of reported cores is larger than the number of
available cores.

For such a system you will need to configure the
`KUMO_AVAILABLE_PARALLELISM` environment variable for each kumo
service running on your system. With these environment files you
can do that simply by creating `/opt/kumomta/etc/kumo-common.env`
with a line like this inside:

```
KUMO_AVAILABLE_PARALLELISM=48
```
2025-04-03 07:26:15 -07:00
Wez Furlong 3fc4bc67d9 queue/strategy.rs: adjust when we start the v1 singleton wheel
Running the lockbud deadlock detector over the code, it thought that the
Once based initialization of the wheels might recursively attempt to
lock an internal mutex.

Seems like a false positive to me, but if it could trigger, it would
only be on startup, and we've had no reports of this being a thing.

Regardless, it made lockbud think really hard about it for just under 7 hours,
and adjusting the logic makes lockbud run in just under a minute, so
it's worth appeasing it.

Adjusting the initialization/insertion logic to look more like
the v2 case makes lockbud happy and continues to pass the
integration test suite.

```json
      {
        "DoubleLock": {
          "bug_kind": "DoubleLock",
          "possibility": "Probably",
          "diagnosis": {
            "first_lock_type": "ParkingLotMutex(timeq::TimeQ<message::message::WeakMessage>)",
            "first_lock_span": "crates/kumod/src/queue/strategy.rs:204:23: 204:45 (#0)",
            "second_lock_type": "ParkingLotMutex(timeq::TimeQ<message::message::WeakMessage>)",
            "second_lock_span": "crates/kumod/src/queue/maintainer.rs:278:17: 278:26 (#0)",
            "callchains": [
              [
                [
                  "crates/kumod/src/queue/strategy.rs:206:25: 206:51 (#0)"
                ],
                [
                  "crates/kumod/src/queue/maintainer.rs:357:5: 363:7 (#0)"
                ],
                [],
                [
                  "/home/wez/.rustup/toolchains/nightly-2025-02-01-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sync/poison/once.rs:158:41: 158:60 (#0)"
                ],
                [
                  "crates/kumod/src/queue/maintainer.rs:358:9: 362:11 (#0)"
                ],
                [],
                [
                  "crates/kumod/src/queue/maintainer.rs:348:17: 348:36 (#0)"
                ],
                [
                  "/home/wez/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.44.1/src/runtime/runtime.rs:342:13: 342:74 (#0)"
                ],
                [
                  "/home/wez/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.44.1/src/runtime/runtime.rs:368:47: 368:88 (#0)"
                ],
                [],
                [],
                [
                  "/home/wez/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.44.1/src/runtime/scheduler/current_thread/mod.rs:211:49: 211:73 (#0)"
                ],
                [
                  "/home/wez/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tracing-0.1.41/src/instrument.rs:321:9: 321:23 (#0)"
                ],
                [
                  "crates/kumod/src/queue/maintainer.rs:359:56: 359:61 (#14652)"
                ],
                [
                  "crates/kumod/src/queue/maintainer.rs:290:39: 290:44 (#0)"
                ]
              ],
              ]
          }
        }
      }
```
2025-04-02 16:26:27 -07:00