some fixes again

This commit is contained in:
Ayzen
2026-06-05 17:50:59 +03:00
parent bbea744459
commit 3c30a12d4a
24 changed files with 209 additions and 157 deletions
@@ -149,6 +149,12 @@ void DataPreprocessor::run(const std::atomic<bool>& stop_requested) {
const auto preprocessed_collection = preprocess_collection(raw_collection);
publish_preprocessed_collection(preprocessed_collection);
} catch (const std::exception& exc) {
// A ring-slot-too-small failure is a permanent config error (the slot
// cannot hold a serialized collection): swallowing it would silently
// drop every collection forever, so fail fast and let the operator fix it.
if (std::string(exc.what()).find("slot is too small") != std::string::npos) {
throw;
}
// A single malformed or transiently-bad collection must not kill the
// long-running preprocessor: drop it and keep serving the next sweep.
// Logging is throttled so a persistent error cannot flood the log.
@@ -148,6 +148,12 @@ void DataProcessor::run(const std::atomic<bool>& stop_requested) {
std::this_thread::sleep_for(std::chrono::milliseconds(config_.runtime.idle_sleep_ms));
} catch (const std::exception& exc) {
// A ring-slot-too-small failure is a permanent config error (the slot
// cannot hold a serialized collection): swallowing it would silently
// drop every collection forever, so fail fast and let the operator fix it.
if (std::string(exc.what()).find("slot is too small") != std::string::npos) {
throw;
}
// A single bad collection (torn ring slot, decode/processing error) must
// not kill the long-running processor: drop it and keep going. Throttle
// logging and pause briefly so a persistent error cannot busy-spin/flood.
@@ -18,14 +18,15 @@
namespace radar::locator {
// Bounded, in-memory packet queue used by the per-client writer thread.
// Marking the queue as full closes the client (back-pressure by disconnect),
// matching the semantics of the previous Python implementation.
// Latest-wins: when full, the oldest queued packet(s) are dropped so a slow
// client always advances toward the freshest result. A slow client is never
// disconnected (freshness over completeness; bounded memory).
class ClientQueue {
public:
explicit ClientQueue(std::size_t capacity);
// Push a packet onto the queue. Returns false if the queue is full or has
// been closed; the caller is expected to disconnect the client in that case.
// Push a packet onto the queue, dropping the oldest entry first if full.
// Returns false ONLY when the queue is closed (the session is shutting down).
[[nodiscard]] auto try_push(std::vector<std::uint8_t> packet) -> bool;
// Block until a packet is available or the queue is closed.
@@ -68,8 +69,8 @@ class ClientSession {
// timestamp slot records when, so the server can expire stale speeds.
void start(std::atomic<double>& shared_vlc_slot, std::atomic<std::int64_t>& shared_vlc_at_ns);
// Enqueue one outbound packet. Disconnects this session if the queue is
// already full or the writer has stopped.
// Enqueue one outbound packet. Never disconnects a slow client: a full queue
// drops its oldest entry (latest-wins). A no-op once the session has stopped.
void enqueue(std::vector<std::uint8_t> packet);
// Initiate teardown of this client (idempotent): closes the queue and
@@ -107,9 +108,9 @@ class ClientSession {
// * Threading: one acceptor thread + two threads per connected client. The
// producer (data_processor) calls publish() synchronously; that call is
// non-blocking and never throws for typical operation.
// * Back-pressure: each client has its own bounded outbound queue. If a
// client is too slow to drain, the next publish() drops it (matches the
// prior Python service). Other clients are unaffected.
// * Back-pressure: each client has its own bounded outbound queue. A client
// too slow to drain is never disconnected; its queue drops the oldest
// packet(s) (latest-wins) so it keeps the freshest data. Clients are isolated.
// * Latest-snapshot: the most recently published packet is cached and sent
// to every newly connected client before any new packets are forwarded.
// * Lifetime: `start()` may throw on listen failure. `stop()` is idempotent