Skip to content

Commit 4d6901c

Browse files
authored
Merge pull request #22 from zetroot/feature/better-schedulling
+semver: feature
2 parents 498f79e + 7d94e63 commit 4d6901c

File tree

6 files changed

+76
-49
lines changed

6 files changed

+76
-49
lines changed

src/NTorSpectator.Observer/NTorSpectator.Observer.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
1414
<PackageReference Include="NeoSmart.AsyncLock" Version="3.2.1" />
1515
<PackageReference Include="prometheus-net.AspNetCore" Version="8.0.0" />
16+
<PackageReference Include="Quartz.AspNetCore" Version="3.6.2" />
1617
<PackageReference Include="Refit" Version="6.3.2" />
1718
<PackageReference Include="Refit.HttpClientFactory" Version="6.3.2" />
1819
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0" />

src/NTorSpectator.Observer/Program.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using NTorSpectator.Observer.TorIntegration;
77
using NTorSpectator.Services;
88
using Prometheus;
9+
using Quartz;
910
using Refit;
1011
using Serilog;
1112
using Serilog.Formatting.Compact;
@@ -39,7 +40,21 @@
3940
.AddBizLogic()
4041
.AddDatabase(builder.Configuration)
4142
.AddTransient<TorControlManager>()
42-
.AddHostedService<Spectator>();
43+
.AddTransient<SpectatorJob>()
44+
.AddHostedService<SitesUpdater>();
45+
46+
builder.Services.AddQuartz(cfg =>
47+
{
48+
cfg.UseMicrosoftDependencyInjectionJobFactory();
49+
50+
var jobDetail = JobBuilder.Create<SpectatorJob>()
51+
.WithDescription("Tor spectator job")
52+
.WithIdentity("tor-spectator")
53+
.Build();
54+
cfg.AddJob<SpectatorJob>(jobKey: jobDetail.Key, configure: j => {});
55+
cfg.AddTrigger(t => t.WithCronSchedule("0 0 * * * ?").ForJob(jobDetail));
56+
});
57+
builder.Services.AddQuartzServer(cfg => cfg.WaitForJobsToComplete = false);
4358

4459
builder.Services
4560
.AddRefitClient<IMastodonClient>(sp =>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Microsoft.Extensions.Options;
2+
using NTorSpectator.Services;
3+
4+
namespace NTorSpectator.Observer.Services;
5+
6+
public class SitesUpdater : BackgroundService
7+
{
8+
private readonly ILogger<SitesUpdater> _logger;
9+
private readonly string _torSitesFile;
10+
private readonly ISitesCatalogue _sitesCatalogue;
11+
12+
public SitesUpdater(ILogger<SitesUpdater> logger, IOptions<SpectatorSettings> opts, ISitesCatalogue sitesCatalogue)
13+
{
14+
_logger = logger;
15+
_sitesCatalogue = sitesCatalogue;
16+
_torSitesFile = opts.Value.SiteList;
17+
}
18+
19+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
20+
{
21+
if (!File.Exists(_torSitesFile))
22+
{
23+
_logger.LogWarning("Tor sites file is not found at path {TorSitesFilePath}. Exiting", _torSitesFile);
24+
return;
25+
}
26+
27+
var sites = await File.ReadAllLinesAsync(_torSitesFile);
28+
foreach (var site in sites)
29+
{
30+
if (string.IsNullOrWhiteSpace(site))
31+
continue;
32+
await _sitesCatalogue.AddIfNotExists(site);
33+
}
34+
_logger.LogDebug("Finished adding sites");
35+
}
36+
}
Lines changed: 16 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,36 @@
1-
using Microsoft.Extensions.Options;
21
using NTorSpectator.Observer.TorIntegration;
32
using NTorSpectator.Services;
43
using NTorSpectator.Services.Models;
4+
using Quartz;
55

66
namespace NTorSpectator.Observer.Services;
77

8-
public class Spectator : BackgroundService
8+
public class SpectatorJob : IJob
99
{
10-
private readonly ILogger<Spectator> _logger;
11-
private readonly TorControlManager _torControl;
12-
private readonly string _torSitesFile;
13-
private readonly TimeSpan _cooldown;
10+
private readonly ILogger<SpectatorJob> _logger;
1411
private readonly ISitesCatalogue _sitesCatalogue;
12+
private readonly TorControlManager _torControl;
1513
private readonly ISiteObserver _siteObserver;
1614

17-
public Spectator(ILogger<Spectator> logger, TorControlManager torControl, IOptions<SpectatorSettings> opts, ISitesCatalogue sitesCatalogue, ISiteObserver siteObserver)
15+
public SpectatorJob(ILogger<SpectatorJob> logger, ISitesCatalogue sitesCatalogue, TorControlManager torControl, ISiteObserver siteObserver)
1816
{
1917
_logger = logger;
20-
_torControl = torControl;
2118
_sitesCatalogue = sitesCatalogue;
19+
_torControl = torControl;
2220
_siteObserver = siteObserver;
23-
_torSitesFile = opts.Value.SiteList;
24-
_cooldown = opts.Value.CooldownInterval;
25-
}
26-
27-
public bool IsRunning { get; private set; }
28-
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
29-
{
30-
try
31-
{
32-
IsRunning = true;
33-
await UpdateSites();
34-
while (!stoppingToken.IsCancellationRequested)
35-
{
36-
await Watch();
37-
await Task.Delay(_cooldown, stoppingToken);
38-
}
39-
}
40-
finally
41-
{
42-
IsRunning = false;
43-
}
4421
}
4522

46-
private async Task Watch()
23+
public async Task Execute(IJobExecutionContext context)
4724
{
25+
_logger.LogDebug("Starting sites observations");
4826
var sites = await _sitesCatalogue.GetAllSites();
49-
var siteQueue = new Queue<QueuedSite>(sites.Select(x => new QueuedSite(x, 0)));
27+
_logger.LogDebug("Got {Count} sites to observe", sites.Count);
5028

29+
var siteQueue = new Queue<QueuedSite>(sites.Select(x => new QueuedSite(x, 0)));
5130
while(siteQueue.TryDequeue(out var queuedSite))
5231
{
5332
using var _ = _logger.BeginScope(new Dictionary<string, object> { { "HiddenService", queuedSite.Site.SiteUri } });
33+
_logger.LogDebug("Starting observations on the next site");
5434
try
5535
{
5636
var observations = await ObserveSite(queuedSite.Site.SiteUri);
@@ -65,6 +45,7 @@ private async Task Watch()
6545
continue;
6646
}
6747
}
48+
_logger.LogDebug("Site seems to be up");
6849
await _siteObserver.AddNewObservation(queuedSite.Site.SiteUri, observations.IsOk);
6950
_logger.LogInformation("Site observed");
7051
}
@@ -73,28 +54,16 @@ private async Task Watch()
7354
_logger.LogError(e, "Observation for site failed");
7455
}
7556
}
57+
_logger.LogDebug("The queue is finally empty, observations finished");
7658
}
77-
78-
private async Task UpdateSites()
79-
{
80-
var sites = await File.ReadAllLinesAsync(_torSitesFile);
81-
foreach (var site in sites)
82-
{
83-
await _sitesCatalogue.AddIfNotExists(site);
84-
}
85-
}
59+
60+
private record QueuedSite(Site Site, int ObservationsCount);
61+
8662
private async Task<TorWatchResults> ObserveSite(string site)
8763
{
8864
var torReply = await _torControl.HsFetch(site);
8965
var positive = torReply.Count(x => x.Action == HsDescAction.Received);
9066
var negative = torReply.Count(x => x.Action == HsDescAction.Failed);
9167
return new(site, positive, negative);
9268
}
93-
94-
private record QueuedSite(Site Site, int ObservationsCount);
95-
}
96-
97-
public record TorWatchResults(string Site, int Positive, int Negative)
98-
{
99-
public bool IsOk => Positive > 0;
10069
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace NTorSpectator.Observer.Services;
2+
3+
public record TorWatchResults(string Site, int Positive, int Negative)
4+
{
5+
public bool IsOk => Positive > 0;
6+
}

src/NTorSpectator.Observer/TorIntegration/TorControlManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public async Task<IReadOnlyCollection<HsDescEventReply>> HsFetch(string serviceD
8686
_logger.LogTrace("Received {Count} messages", responses.Length);
8787

8888
var replies = responses.Select(x => TorReply.TryParse(x, out var reply) ? reply : null).Where(x => x != null).ToList();
89-
_logger.LogInformation("Parsed {Count}", replies.Count);
89+
_logger.LogDebug("Parsed {Count}", replies.Count);
9090
var hsDescEvents = replies.OfType<HsDescEventReply>().Where(x => x.Action is HsDescAction.Received or HsDescAction.Failed).ToList();
9191
results.AddRange(hsDescEvents);
9292
if (results.Any(x => x.Action == HsDescAction.Received))

0 commit comments

Comments
 (0)