Skip to content

Commit 42679a1

Browse files
committed
feat: [torrust#1403] collect http tracker instance metrics
It creates services per HTTP tracker instance (server bound to a socket address) to collect metrics only for that instace. There should be test failing becuase any server can use only one event sender and metrics repository. Therefore global metrics should not be updated. I think the problem is there are no E2E tests for statistics. There are only integration tests at the HTTP Core pacakge level.
1 parent 734393d commit 42679a1

File tree

4 files changed

+90
-16
lines changed

4 files changed

+90
-16
lines changed

src/app.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use crate::container::AppContainer;
3838
/// - Can't retrieve tracker keys from database.
3939
/// - Can't load whitelist from database.
4040
#[instrument(skip(config, app_container))]
41-
pub async fn start(config: &Configuration, app_container: &Arc<AppContainer>) -> Vec<JoinHandle<()>> {
41+
pub async fn start(config: &Configuration, app_container: &mut AppContainer) -> Vec<JoinHandle<()>> {
4242
if config.http_api.is_none()
4343
&& (config.udp_trackers.is_none() || config.udp_trackers.as_ref().map_or(true, std::vec::Vec::is_empty))
4444
&& (config.http_trackers.is_none() || config.http_trackers.as_ref().map_or(true, std::vec::Vec::is_empty))
@@ -94,7 +94,7 @@ pub async fn start(config: &Configuration, app_container: &Arc<AppContainer>) ->
9494
if let Some(http_trackers) = &config.http_trackers {
9595
for http_tracker_config in http_trackers {
9696
let http_tracker_config = Arc::new(http_tracker_config.clone());
97-
let http_tracker_container = Arc::new(app_container.http_tracker_container(&http_tracker_config));
97+
let http_tracker_container = Arc::new(app_container.http_tracker_container(&http_tracker_config).await);
9898

9999
if let Some(job) = http_tracker::start_job(
100100
http_tracker_container,

src/console/profiling.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@
157157
//! kcachegrind callgrind.out
158158
//! ```
159159
use std::env;
160-
use std::sync::Arc;
161160
use std::time::Duration;
162161

163162
use tokio::time::sleep;
@@ -180,11 +179,9 @@ pub async fn run() {
180179
return;
181180
};
182181

183-
let (config, app_container) = bootstrap::app::setup();
182+
let (config, mut app_container) = bootstrap::app::setup();
184183

185-
let app_container = Arc::new(app_container);
186-
187-
let jobs = app::start(&config, &app_container).await;
184+
let jobs = app::start(&config, &mut app_container).await;
188185

189186
// Run the tracker for a fixed duration
190187
let run_duration = sleep(Duration::from_secs(duration_secs));

src/container.rs

+84-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashMap;
2+
use std::net::SocketAddr;
13
use std::sync::Arc;
24

35
use bittorrent_http_tracker_core::container::HttpTrackerCoreContainer;
@@ -65,6 +67,9 @@ pub struct AppContainer {
6567
pub http_announce_service: Arc<bittorrent_http_tracker_core::services::announce::AnnounceService>,
6668
pub http_scrape_service: Arc<bittorrent_http_tracker_core::services::scrape::ScrapeService>,
6769

70+
// HTTP Tracker Server Containers (one container per HTTP Tracker)
71+
pub http_server_instance_containers: Arc<RwLock<HttpTrackerInstanceContainers>>,
72+
6873
// UDP Tracker Server Services
6974
pub udp_server_stats_event_sender: Arc<Option<Box<dyn torrust_udp_tracker_server::event::sender::Sender>>>,
7075
pub udp_server_stats_repository: Arc<torrust_udp_tracker_server::statistics::repository::Repository>,
@@ -96,6 +101,9 @@ impl AppContainer {
96101
http_stats_event_sender.clone(),
97102
));
98103

104+
// HTTP Tracker Server Containers (one container per HTTP Tracker)
105+
let http_server_instance_containers = Arc::new(RwLock::new(HttpTrackerInstanceContainers::default()));
106+
99107
// UDP Tracker Core Services
100108
let (udp_core_stats_event_sender, udp_core_stats_repository) =
101109
bittorrent_udp_tracker_core::statistics::setup::factory(configuration.core.tracker_usage_statistics);
@@ -150,14 +158,37 @@ impl AppContainer {
150158
http_announce_service,
151159
http_scrape_service,
152160

161+
// HTTP Tracker Server Containers
162+
http_server_instance_containers,
163+
153164
// UDP Tracker Server Services
154165
udp_server_stats_event_sender,
155166
udp_server_stats_repository,
156167
}
157168
}
158169

159170
#[must_use]
160-
pub fn http_tracker_container(&self, http_tracker_config: &Arc<HttpTracker>) -> HttpTrackerCoreContainer {
171+
pub async fn http_tracker_container(&mut self, http_tracker_config: &Arc<HttpTracker>) -> HttpTrackerCoreContainer {
172+
let http_tracker_instance_container = if let Some(http_tracker_instance_container) = self
173+
.http_server_instance_containers
174+
.read()
175+
.await
176+
.get(&http_tracker_config.bind_address)
177+
.await
178+
{
179+
http_tracker_instance_container
180+
} else {
181+
let http_server_instance_container = Arc::new(HttpTrackerInstanceContainer::initialize(http_tracker_config));
182+
183+
self.http_server_instance_containers
184+
.write()
185+
.await
186+
.insert(http_tracker_config, http_server_instance_container.clone())
187+
.await;
188+
189+
http_server_instance_container
190+
};
191+
161192
HttpTrackerCoreContainer {
162193
core_config: self.core_config.clone(),
163194
announce_handler: self.announce_handler.clone(),
@@ -166,8 +197,8 @@ impl AppContainer {
166197
authentication_service: self.authentication_service.clone(),
167198

168199
http_tracker_config: http_tracker_config.clone(),
169-
http_stats_event_sender: self.http_stats_event_sender.clone(),
170-
http_stats_repository: self.http_stats_repository.clone(),
200+
http_stats_event_sender: http_tracker_instance_container.http_core_stats_event_sender.clone(),
201+
http_stats_repository: http_tracker_instance_container.http_core_stats_repository.clone(),
171202
announce_service: self.http_announce_service.clone(),
172203
scrape_service: self.http_scrape_service.clone(),
173204
}
@@ -214,3 +245,53 @@ impl AppContainer {
214245
}
215246
}
216247
}
248+
249+
/// Container for each HTTP Tracker Server instance.
250+
///
251+
/// Each instance runs on a different socket address. These services are not
252+
/// shared between instances.
253+
#[derive(Default)]
254+
pub struct HttpTrackerInstanceContainers {
255+
instances: RwLock<HashMap<SocketAddr, Arc<HttpTrackerInstanceContainer>>>,
256+
}
257+
258+
impl HttpTrackerInstanceContainers {
259+
pub async fn insert(
260+
&mut self,
261+
http_tracker_config: &Arc<HttpTracker>,
262+
http_server_instance_container: Arc<HttpTrackerInstanceContainer>,
263+
) {
264+
self.instances
265+
.write()
266+
.await
267+
.insert(http_tracker_config.bind_address, http_server_instance_container);
268+
}
269+
270+
#[must_use]
271+
pub async fn get(&self, socket_addr: &SocketAddr) -> Option<Arc<HttpTrackerInstanceContainer>> {
272+
self.instances.read().await.get(socket_addr).cloned()
273+
}
274+
}
275+
276+
/// Container for HTTP Tracker Server instances.
277+
#[derive(Clone, Default)]
278+
pub struct HttpTrackerInstanceContainer {
279+
pub http_core_stats_event_sender: Arc<Option<Box<dyn bittorrent_http_tracker_core::event::sender::Sender>>>,
280+
pub http_core_stats_repository: Arc<bittorrent_http_tracker_core::statistics::repository::Repository>,
281+
}
282+
283+
impl HttpTrackerInstanceContainer {
284+
#[must_use]
285+
pub fn initialize(configuration: &HttpTracker) -> Self {
286+
let (http_core_stats_event_sender, http_core_stats_repository) =
287+
bittorrent_http_tracker_core::statistics::setup::factory(configuration.tracker_usage_statistics);
288+
289+
let http_core_stats_event_sender = Arc::new(http_core_stats_event_sender);
290+
let http_core_stats_repository = Arc::new(http_core_stats_repository);
291+
292+
Self {
293+
http_core_stats_event_sender,
294+
http_core_stats_repository,
295+
}
296+
}
297+
}

src/main.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
use std::sync::Arc;
2-
31
use torrust_tracker_lib::{app, bootstrap};
42

53
#[tokio::main]
64
async fn main() {
7-
let (config, app_container) = bootstrap::app::setup();
8-
9-
let app_container = Arc::new(app_container);
5+
let (config, mut app_container) = bootstrap::app::setup();
106

11-
let jobs = app::start(&config, &app_container).await;
7+
let jobs = app::start(&config, &mut app_container).await;
128

139
// handle the signals
1410
tokio::select! {

0 commit comments

Comments
 (0)