From cf0b6907f79f9fd9bc088a12aff24e5206e3b699 Mon Sep 17 00:00:00 2001 From: smoh Date: Thu, 11 Dec 2025 17:54:18 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9E=91=EC=97=85=20=EC=8B=9C=EA=B0=84=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=9D=B4=EC=8A=88=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A0=80=EC=9E=A5=20=ED=99=95=EC=9D=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/AppDbService.cs | 27 +++++++++++++++++++-------- Services/Mappers/JiraIssueMapper.cs | 6 +++--- Workers/AppDbWorker.cs | 1 - Workers/JiraWorker.cs | 29 ++++++++++++++++++++++++++--- Workers/TriliumWorker.cs | 8 ++++---- 5 files changed, 52 insertions(+), 19 deletions(-) diff --git a/Services/AppDbService.cs b/Services/AppDbService.cs index 1f71396..48f73c1 100644 --- a/Services/AppDbService.cs +++ b/Services/AppDbService.cs @@ -94,16 +94,20 @@ public class AppDbService } #endregion Table: Configs - - public async Task UpsertJiraIssueAsync(JiraIssue issue, CancellationToken ct = default) + #region Table: JiraIssues + public async Task<(bool isInserted, bool isUpdated)> UpsertJiraIssueAsync(JiraIssue issue, CancellationToken ct = default) { try { var existing = await _db.JiraIssues.FindAsync([issue.Key], ct); + bool isInserted = false; + bool isUpdated = false; + if (existing == null) { _db.JiraIssues.Add(issue); + isInserted = true; _log.Debug("Inserting new Jira issue: {key}", issue.Key); } else @@ -122,6 +126,7 @@ public class AppDbService existing.NeedNotify = issue.NeedNotify; _db.JiraIssues.Update(existing); + isUpdated = true; _log.Debug("Updating existing Jira issue: {key}", issue.Key); } else @@ -131,6 +136,7 @@ public class AppDbService } await _db.SaveChangesAsync(ct); + return (isInserted, isUpdated); } catch (Exception ex) { @@ -139,27 +145,29 @@ public class AppDbService } } - public async Task UpsertJiraIssuesBatchAsync(IEnumerable issues, CancellationToken ct = default) + public async Task<(List inserted, List updated)> UpsertJiraIssuesBatchAsync(IEnumerable issues, CancellationToken ct = default) { try { var issueList = issues.ToList(); if (!issueList.Any()) - return; + return (new List(), new List()); var keys = issueList.Select(i => i.Key).ToList(); var existingIssues = await _db.JiraIssues .Where(ji => keys.Contains(ji.Key)) .ToDictionaryAsync(ji => ji.Key, ct); - int insertCount = 0, updateCount = 0, skipCount = 0; + var insertedKeys = new List(); + var updatedKeys = new List(); + int skipCount = 0; foreach (var issue in issueList) { if (!existingIssues.TryGetValue(issue.Key, out var existing)) { _db.JiraIssues.Add(issue); - insertCount++; + insertedKeys.Add(issue.Key); } else if (issue.Updated > existing.Updated) { @@ -175,7 +183,7 @@ public class AppDbService existing.NeedNotify = issue.NeedNotify; _db.JiraIssues.Update(existing); - updateCount++; + updatedKeys.Add(issue.Key); } else { @@ -185,7 +193,9 @@ public class AppDbService await _db.SaveChangesAsync(ct); _log.Information("Batch completed: {insert} inserted, {update} updated, {skip} skipped out of {total} issues", - insertCount, updateCount, skipCount, issueList.Count); + insertedKeys.Count, updatedKeys.Count, skipCount, issueList.Count); + + return (insertedKeys, updatedKeys); } catch (Exception ex) { @@ -193,4 +203,5 @@ public class AppDbService throw; } } + #endregion Table: JiraIssues } diff --git a/Services/Mappers/JiraIssueMapper.cs b/Services/Mappers/JiraIssueMapper.cs index 5a4100a..4feb73f 100644 --- a/Services/Mappers/JiraIssueMapper.cs +++ b/Services/Mappers/JiraIssueMapper.cs @@ -16,9 +16,9 @@ public static class JiraIssueMapper Status = issue.fields.status?.description ?? string.Empty, Assignee = issue.fields.assignee?.displayName ?? string.Empty, Manager = issue.fields.reporter?.displayName ?? string.Empty, - Due = issue.fields.duedate?.ToUniversalTime() ?? DateTimeOffset.MinValue, - Updated = issue.fields.UpdatedAt, - Published = DateTimeOffset.MinValue, + Due = issue.fields.duedate?.ToUniversalTime() ?? DateTimeOffset.MinValue.ToUniversalTime(), + Updated = issue.fields.UpdatedAt.ToUniversalTime(), + Published = DateTimeOffset.MinValue.ToUniversalTime(), ObjectId = null, NeedNotify = 0 }; diff --git a/Workers/AppDbWorker.cs b/Workers/AppDbWorker.cs index 04e7955..0d7efa5 100644 --- a/Workers/AppDbWorker.cs +++ b/Workers/AppDbWorker.cs @@ -78,7 +78,6 @@ public class AppDbWorker : BackgroundService var db = scope.ServiceProvider.GetRequiredService(); var jiraIssues = batch.Select(i => i.ToEntity()).ToList(); await db.UpsertJiraIssuesBatchAsync(jiraIssues, stoppingToken); - _log.Information("Processed batch of {count} Jira issues", batch.Count); batch.Clear(); } diff --git a/Workers/JiraWorker.cs b/Workers/JiraWorker.cs index 8cbcec5..484efae 100644 --- a/Workers/JiraWorker.cs +++ b/Workers/JiraWorker.cs @@ -11,13 +11,16 @@ public class JiraWorker : BackgroundService { private readonly Serilog.ILogger _log; private readonly AppConfigs _configs; + private readonly IServiceScopeFactory _scopeFactory; // Singleton services cannot directly inject Scoped services. private readonly JiraService _jira; private readonly Channel _issueChannel; - public JiraWorker(AppConfigs configs, JiraService jaraService, Channel issueChannel) + public JiraWorker(AppConfigs configs, IServiceScopeFactory serviceScopeFactory, + JiraService jaraService, Channel issueChannel) { _log = Log.ForContext(); ; _configs = configs; + _scopeFactory = serviceScopeFactory; _jira = jaraService; _issueChannel = issueChannel; } @@ -28,15 +31,27 @@ public class JiraWorker : BackgroundService { _log.Debug("Worker running at: {time}", DateTimeOffset.Now); - var lastFetchTime = DateTimeOffset.Parse(_configs.RuntimeConfigs[Consts.ConfigLastFetchTimeKey]); + var configLastFetchTime = _configs.RuntimeConfigs.GetValueOrDefault(Consts.ConfigLastFetchTimeKey); + if (string.IsNullOrEmpty(configLastFetchTime)) + { + using (var scope = _scopeFactory.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + 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); var issueList = new List(); + var currentFetchTime = DateTimeOffset.Now; foreach (var targetProject in _configs.AppSettings.Jira.TargetProjects) { int startAt = 0, total = 0; do { - var response = await _jira.FetchJiraIssuesAsync(DateTimeOffset.Now.AddDays(-1), targetProject, startAt, stoppingToken); + var response = await _jira.FetchJiraIssuesAsync(lastFetchTime, targetProject, startAt, stoppingToken); if (response != null) { total = response.total; @@ -49,6 +64,14 @@ public class JiraWorker : BackgroundService { await _issueChannel.Writer.WriteAsync(item, stoppingToken); } + + using (var scope = _scopeFactory.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + // 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"); + } await Task.Delay(_configs.AppSettings.Jira.FetchInterval * 1000, stoppingToken); } } diff --git a/Workers/TriliumWorker.cs b/Workers/TriliumWorker.cs index f3a51bd..b681778 100644 --- a/Workers/TriliumWorker.cs +++ b/Workers/TriliumWorker.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Options; using Serilog; using System.Threading.Channels; +using TriliumMind.Data.Entities; using TriliumMind.Models; using TriliumMind.Services; @@ -23,11 +24,10 @@ public class TriliumWorker : BackgroundService protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - await foreach(var item in _issueChannel.Reader.ReadAllAsync(stoppingToken)) + while (!stoppingToken.IsCancellationRequested) { - _log.Information("Processing issue {issue_key} - {issue_summary}", item.key, item.fields.summary); - // Add your processing logic here - //await _triliumService.FettchPageContentsAsync(item); + _log.Debug("Worker running at: {time}", DateTimeOffset.Now); + await Task.Delay(10 *1000, stoppingToken); } } }