♻️ sync owner migration and facade thinning

This commit is contained in:
Nanaloveyuki
2026-07-07 20:03:22 +08:00
parent 5d9924026e
commit e3097ba4fc
79 changed files with 5255 additions and 3191 deletions
+11 -5
View File
@@ -2,7 +2,7 @@
name: async-logger
group: api
category: async
update-time: 20260614
update-time: 20260707
description: Create an async logger with bounded queueing, overflow policy, lifecycle helpers, background run control, and a raising flush callback.
key-word:
- async
@@ -23,7 +23,7 @@ pub fn[S] async_logger(
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
target~ : String = "",
flush~ : (S) -> Int raise = fn(_) { 0 },
flush~ : (S) -> Unit raise = fn(_) { () },
) -> AsyncLogger[S] {}
```
@@ -33,7 +33,7 @@ pub fn[S] async_logger(
- `config : AsyncLoggerConfig` - Queue size, overflow behavior, batching, linger, and flush policy.
- `min_level : Level` - Level gate applied before enqueue.
- `target : String` - Default target for emitted records.
- `flush : (S) -> Int raise` - Flush callback used by batch/shutdown flush policies and allowed to raise if sink flushing fails.
- `flush : (S) -> Unit raise` - Flush callback used by batch/shutdown flush policies and allowed to raise if sink flushing fails.
#### output
@@ -45,7 +45,7 @@ Detailed rules explaining key parameters and behaviors
- `async_logger(...)` only builds the logger. Actual background draining is started by `run()`.
- `async_logger(...)` returns the full `AsyncLogger[S]` surface directly. It is therefore the underlying constructor used by both application-facing async aliases and the narrower `LibraryAsyncLogger[S]` wrapper line.
- The constructed logger starts with `is_closed=false`, `is_running=false`, `has_failed=false`, `last_error=""`, and zeroed pending/dropped counters.
- The constructed logger starts in lifecycle phase `ready`, with `last_error=""` and zeroed pending/dropped counters.
- The constructed logger also keeps the core async target contract unchanged: `log(..., target=...)` can override the target for one call, while fixed-level helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
- Unlike synchronous `Logger`, async `with_context_fields(...)` and `bind(...)` preserve the visible `AsyncLogger[S]` type because shared fields are stored directly on the async logger value instead of being modeled as a separate sink wrapper.
- `ApplicationAsyncLogger` and `ApplicationTextAsyncLogger` are only alias names over concrete `AsyncLogger[...]` shapes, so they keep the same lifecycle, queue, failure, and state helpers without adding a wrapper layer.
@@ -54,10 +54,15 @@ Detailed rules explaining key parameters and behaviors
- `src-async` is designed for `native / llvm / js / wasm / wasm-gc`, but current release-facing local verification is stronger for `native / js / wasm / wasm-gc` than for `llvm`.
- `llvm` should currently be read as experimental and locally unverified in this environment rather than as a stable checked target.
- `flush` is used only when batch or shutdown policy wants explicit flushing.
- The callback expresses attempted flush timing and failure, not a returned progress count contract.
- If the supplied flush callback raises, worker failure state is recorded through `has_failed()` and `last_error()`.
- `wait_idle()` is failure-aware rather than a pure backlog-to-zero guarantee. If a worker failure sets `has_failed=true`, waiting stops early and the logger can still report `pending_count() > 0` until later cleanup or restart work happens.
- A later `run()` attempt starts by clearing stale failure state back to `has_failed=false` and `last_error=""` before it resumes draining any backlog still left in the queue.
- The exact behavior of late log attempts after closure is runtime-dependent, so callers should use lifecycle helpers like `is_closed()` and `shutdown()` instead of assuming identical post-close enqueue semantics everywhere.
- `state()` exposes the stronger lifecycle conclusion through `phase`, plus derived reads such as `backlog_retained`, `can_rerun`, and `terminal` so callers do not have to infer these states from raw flag combinations.
- Late log attempts after closure are rejected in the shared async log path before patch/filter work runs, so post-close side effects no longer vary by backend.
- `run()` now enforces a single-worker contract and raises `AsyncLoggerAlreadyRunning` when a second worker startup is attempted for the same live logger.
- `run()` also rejects already-closed loggers with `AsyncLoggerClosed`, which keeps rerun semantics aligned with the stronger lifecycle model: rerun is for retained `failed` backlog, not for terminal closed phases.
- `shutdown()` now always waits for any active worker to finish and converts retained post-failure backlog into dropped records before returning.
- Queue overflow behavior depends on `AsyncOverflowPolicy`.
### How to Use
@@ -125,6 +130,7 @@ e.g.:
- If the logger is closed, further enqueue attempts stop being normal active logging operations.
- If queue drain fails internally, runtime state can reflect that through `has_failed()` and `last_error()`.
- If a second worker startup is attempted while `is_running()` is already true, `run()` raises `AsyncLoggerAlreadyRunning`.
### Notes