2025-12-11 10:20:10 +09:00
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
|
|
using Serilog;
|
|
|
|
|
|
using System.Numerics;
|
|
|
|
|
|
using System.Threading.Channels;
|
|
|
|
|
|
using TriliumMind.Models;
|
|
|
|
|
|
using TriliumMind.Services;
|
|
|
|
|
|
|
|
|
|
|
|
namespace TriliumMind.Workers;
|
|
|
|
|
|
|
|
|
|
|
|
public class JiraWorker : BackgroundService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly Serilog.ILogger _log;
|
|
|
|
|
|
private readonly AppConfigs _configs;
|
2025-12-11 17:54:18 +09:00
|
|
|
|
private readonly IServiceScopeFactory _scopeFactory; // Singleton services cannot directly inject Scoped services.
|
2025-12-11 10:20:10 +09:00
|
|
|
|
private readonly JiraService _jira;
|
|
|
|
|
|
private readonly Channel<Issue> _issueChannel;
|
|
|
|
|
|
|
2025-12-11 17:54:18 +09:00
|
|
|
|
public JiraWorker(AppConfigs configs, IServiceScopeFactory serviceScopeFactory,
|
|
|
|
|
|
JiraService jaraService, Channel<Issue> issueChannel)
|
2025-12-11 10:20:10 +09:00
|
|
|
|
{
|
|
|
|
|
|
_log = Log.ForContext<JiraWorker>(); ;
|
|
|
|
|
|
_configs = configs;
|
2025-12-11 17:54:18 +09:00
|
|
|
|
_scopeFactory = serviceScopeFactory;
|
2025-12-11 10:20:10 +09:00
|
|
|
|
_jira = jaraService;
|
|
|
|
|
|
_issueChannel = issueChannel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
|
|
|
|
{
|
|
|
|
|
|
_log.Debug("Worker running at: {time}", DateTimeOffset.Now);
|
|
|
|
|
|
|
2025-12-11 17:54:18 +09:00
|
|
|
|
var configLastFetchTime = _configs.RuntimeConfigs.GetValueOrDefault(Consts.ConfigLastFetchTimeKey);
|
|
|
|
|
|
if (string.IsNullOrEmpty(configLastFetchTime))
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var scope = _scopeFactory.CreateScope())
|
|
|
|
|
|
{
|
|
|
|
|
|
var db = scope.ServiceProvider.GetRequiredService<AppDbService>();
|
|
|
|
|
|
var lastFetchTimeText = await db.GetConfigAsync(Consts.ConfigLastFetchTimeKey);
|
|
|
|
|
|
configLastFetchTime = (lastFetchTimeText != null)
|
|
|
|
|
|
? lastFetchTimeText : DateTimeOffset.Now.AddDays(-1).ToString("yyyy-MM-ddTHH:mm:sszzz");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
var lastFetchTime = DateTimeOffset.Parse(configLastFetchTime);
|
2025-12-11 10:20:10 +09:00
|
|
|
|
|
|
|
|
|
|
var issueList = new List<Issue>();
|
2025-12-11 17:54:18 +09:00
|
|
|
|
var currentFetchTime = DateTimeOffset.Now;
|
2025-12-11 10:20:10 +09:00
|
|
|
|
foreach (var targetProject in _configs.AppSettings.Jira.TargetProjects)
|
|
|
|
|
|
{
|
|
|
|
|
|
int startAt = 0, total = 0;
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
2025-12-11 17:54:18 +09:00
|
|
|
|
var response = await _jira.FetchJiraIssuesAsync(lastFetchTime, targetProject, startAt, stoppingToken);
|
2025-12-11 10:20:10 +09:00
|
|
|
|
if (response != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
total = response.total;
|
|
|
|
|
|
startAt += response.maxResults;
|
|
|
|
|
|
issueList.AddRange(response.issues);
|
|
|
|
|
|
}
|
|
|
|
|
|
} while(startAt < total);
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var item in issueList)
|
|
|
|
|
|
{
|
|
|
|
|
|
await _issueChannel.Writer.WriteAsync(item, stoppingToken);
|
|
|
|
|
|
}
|
2025-12-11 17:54:18 +09:00
|
|
|
|
|
|
|
|
|
|
using (var scope = _scopeFactory.CreateScope())
|
|
|
|
|
|
{
|
|
|
|
|
|
var db = scope.ServiceProvider.GetRequiredService<AppDbService>();
|
|
|
|
|
|
// Update last fetch time
|
|
|
|
|
|
await db.SetConfigAsync(Consts.ConfigLastFetchTimeKey, currentFetchTime.ToString("yyyy-MM-ddTHH:mm:sszzz"));
|
|
|
|
|
|
_configs.RuntimeConfigs[Consts.ConfigLastFetchTimeKey] = currentFetchTime.ToString("yyyy-MM-ddTHH:mm:sszzz");
|
|
|
|
|
|
}
|
2025-12-11 10:20:10 +09:00
|
|
|
|
await Task.Delay(_configs.AppSettings.Jira.FetchInterval * 1000, stoppingToken);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|