141 lines
5.3 KiB
C#

using System;
using AAIntegration.SimmonsBank.API.Configs;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using AAIntegration.SimmonsBank.API.Processes;
using AAIntegration.SimmonsBank.API.Services;
using AAIntegration.SimmonsBank.API.Entities;
using Microsoft.Extensions.Caching.Memory;
namespace AAIntegration.SimmonsBank.API.Workers;
public class PuppeteerWorker : BackgroundService
{
private readonly PuppeteerConfig _config;
private readonly IPuppeteerProcess _puppeteerProcess;
private readonly ILogger<PuppeteerWorker> _logger;
private readonly IMemoryCache _memoryCache;
private readonly IServiceScopeFactory _serviceScopeFactory;
public PuppeteerWorker(
IOptions<PuppeteerConfig> config,
IPuppeteerProcess puppeteerProcess,
ILogger<PuppeteerWorker> logger,
IMemoryCache memoryCache,
IServiceScopeFactory serviceScopeFactory)
{
_config = config.Value;
_puppeteerProcess = puppeteerProcess;
_logger = logger;
_memoryCache = memoryCache;
_serviceScopeFactory = serviceScopeFactory;
}
private IUserService _userService;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
DateTime? lastExecutedOn = null;
bool operationOccurred = false;
using (var scope = _serviceScopeFactory.CreateScope())
{
_userService = scope.ServiceProvider.GetService<IUserService>();
_puppeteerProcess.SetStoppingToken(stoppingToken);
// This is how we keep the app running (in the background)
while (!stoppingToken.IsCancellationRequested)
{
// Keep Alive processing
operationOccurred = await ProcessUsersKeepalive();
_logger.LogInformation($"Operation occurred? {operationOccurred}");
// If no operation occurred, waits before looping again
if (lastExecutedOn != null && operationOccurred == false)
{
await Task.Delay(TimeSpan.FromMinutes(_config.TaskCheckIntervalMinutes), stoppingToken);
}
lastExecutedOn = DateTime.UtcNow;
_logger.LogInformation("PuppeteerWorker executed at: {time}", DateTimeOffset.Now);
}
}
}
private async Task<bool> ProcessUsersKeepalive()
{
bool operationOccurred = false;
foreach (User user in _userService.GetAll().ToList())
{
int ka = _config.KeepAliveIntervalMinutes;
int uka = (int)DateTime.UtcNow.Subtract(GetUserLastExecution(PuppeteerConfigConstants.KeepAliveIntervalMinutes, user.Id)).TotalMinutes;
//_logger.LogInformation($"KeepAlive configured to {ka}. This user hasn't been kept alive in {uka} minute(s).");
if (_config.KeepAliveIntervalMinutes <= (int)DateTime.UtcNow.Subtract(GetUserLastExecution(PuppeteerConfigConstants.KeepAliveIntervalMinutes, user.Id)).TotalMinutes)
{
await _puppeteerProcess.StayLoggedIn(user);
SetUserLastExecution(PuppeteerConfigConstants.KeepAliveIntervalMinutes, user.Id, DateTime.UtcNow);
operationOccurred = true;
_logger.LogInformation($"Operation set to true because of user {user.Id}");
}
}
return operationOccurred;
}
private DateTime GetUserLastExecution(string cacheKey, int userId)
{
var internalKeys = GetLastExecutionCachedDictionary(cacheKey);
if (!internalKeys.TryGetValue(userId, out var lastExecution))
{
_logger.LogInformation($"Could not find userId in '{cacheKey}' cache. Returning '{DateTime.MinValue}'.");
return DateTime.MinValue;
}
_logger.LogInformation($"Just got user {userId} from cache with value {lastExecution}");
return lastExecution;
}
private void SetUserLastExecution(string cacheKey, int userId, DateTime lastExecution)
{
var internalKeys = GetLastExecutionCachedDictionary(cacheKey);
if (internalKeys.ContainsKey(userId))
internalKeys[userId] = lastExecution;
else
internalKeys.Add(userId, lastExecution);
_memoryCache.Set(cacheKey, internalKeys);
_logger.LogInformation($"Just set user {userId} into cache with value {lastExecution}");
}
private Dictionary<int, DateTime> GetLastExecutionCachedDictionary(string cacheKey)
{
// Sets cache if no dictionary is found
if (!_memoryCache.TryGetValue<Dictionary<int, DateTime>>(cacheKey, out var internalKeys))
{
internalKeys = _userService.GetAll()
.ToDictionary(u => u.Id, u => DateTime.MinValue);
_memoryCache.Set(cacheKey, internalKeys);
_logger.LogInformation($"Updated users in '{cacheKey}' cache with new id list.");
}
return internalKeys;
}
private void PrintCacheValues(string cacheKey)
{
_logger.LogInformation($"Printing cache values from '{cacheKey}'");
Dictionary<int, DateTime> internalKeys = GetLastExecutionCachedDictionary(cacheKey);
foreach (KeyValuePair<int, DateTime> entry in internalKeys)
{
_logger.LogInformation($" {entry.Key} <=> {entry.Value}");
}
}
}