Multibuy 2.0: Hotspot/Region Deny Lists & Service Modernization#4
Merged
Multibuy 2.0: Hotspot/Region Deny Lists & Service Modernization#4
Conversation
- Add hotspot_key and region fields to gRPC protocol for filtering - Add configurable hotspot and region deny lists via settings/env vars - Restructure into cli/grpc/metrics modules for better separation - Use task-manager for graceful shutdown of gRPC server and cache cleanup - Use custom-tracing for dynamic log level updates - Add structured metrics module following oracles patterns - Replace old CI workflow with Docker-based base image caching - Add Dockerfile with multi-stage build (base/builder/runner) - Add rust-toolchain.toml pinning to 1.91.1 - Add integration tests for counting, deny lists, and shutdown - Update README with full configuration reference and env vars
Resolve Cargo.toml and Cargo.lock conflicts by keeping our modernized dependencies. Picks up LICENSE and CONTRIBUTING.md from main.
- Replace Mutex<HashMap> with DashMap for per-shard locking under concurrency - Use DashMap entry() API to avoid redundant lookups - Track cache size with AtomicUsize for lock-free accurate metrics - Use Instant instead of SystemTime for cache timestamps - Fail fast on invalid deny list entries at startup - Propagate metrics startup errors instead of swallowing them - Add Default impl for Cache to satisfy clippy - Add non-root user in Dockerfile - Fix stale comment in settings.rs - Add concurrent request and cache expiry integration tests
Extract hotspot/region deny list functionality from the main service into examples/deny_lists.rs and examples/allow_lists.rs. The core service now only handles counting and cache cleanup.
Co-authored-by: Michael Jeffrey <michaeldjeffrey@gmail.com>
Co-authored-by: Michael Jeffrey <michaeldjeffrey@gmail.com>
Remove manual AtomicUsize cache size tracking in favor of gauge increment/set. Drop cache_cleaned_total metric, unused parking_lot dep, and tokio full feature. Switch helium-proto to master and CI to cargo test.
| allow_lists.hotspots.len(), | ||
| allow_lists.regions.len() | ||
| ); | ||
| println!("(empty hotspot list = all hotspots allowed)"); |
Contributor
There was a problem hiding this comment.
Suggested change
| println!("(empty hotspot list = all hotspots allowed)"); |
michaeldjeffrey
approved these changes
Apr 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
hotspot_keyandregionfields so HPR can send hotspot identity and region alongside packet keysdenied=truewhile still incrementing the counter for trackingWhat changed
Protocol & Deny Lists
MultiBuyIncReqV1now includeshotspot_key(bytes) andregion(helium.region enum)MultiBuyIncResV1now includesdenied(bool) — backward compatible (proto3 defaultfalse)denied_hotspots(base58 keys) anddenied_regions(e.g.US915,EU868) in settings or env varsArchitecture
cli/,state,cache,tasks/,metrics/modulesMutex<HashMap>replaced withDashMapfor per-shard locking under concurrent loadAtomicUsizefor lock-free accurate metricsInstantinstead ofSystemTime(immune to clock adjustments)task-manager(from helium/oracles) manages gRPC server and cache cleanup with graceful SIGTERM/SIGINT shutdowncustom-tracingfor dynamic log level updatesclapsubcommand:multi_buy_service -c settings.toml serverMetrics (Prometheus on
:19011)multi_buy_hit_totalmulti_buy_denied_totalmulti_buy_cache_sizemulti_buy_cache_cleaned_totalmulti_buy_request_duration_msCI/CD & Docker
build.yamlwith Docker-basedci.yml(cached base image, parallel fmt/clippy/nextest, Debian packaging + GHCR image ontags)
base→builder→runnerondebian:bookworm-slim) with non-root userrust-toolchain.tomlto 1.91.1Tests
cargo nextest: counting, key independence, hotspot/region deny, empty key, graceful shutdown,100-concurrent-request correctness, cache expiry