using System.Collections.Concurrent; using System.Data; using InServiceQue.Core.Models; using InServiceQue.Core.Repositories; namespace InServiceQue.InMemory; public class TaskRepositoryInMemory: ITaskRepository { //todo: concurrent access here private static int _currentShard; private static ConcurrentDictionary> _quesByType = new(); public void Dispose() { // TODO release managed resources here } public void Insert(QueueTask task) { if (_quesByType.ContainsKey(task.TaskType)) { _quesByType.AddOrUpdate(task.TaskType, (t) => new ConcurrentQueue(new[] { task }), (t, queue) => { queue.Enqueue(task); return queue; } ); } } public async Task InsertAsync(QueueTask task) { Insert(task); await Task.CompletedTask; } public IDbTransaction StartTransaction() { return null; } public async Task StartTransactionAsync() { return await Task.FromResult(null); } public void CommitTransaction(IDbTransaction tx) { } public async Task CommitTransactionAsync(IDbTransaction tx) { await Task.CompletedTask; } public void RollbackTransaction(IDbTransaction tx) { } public async Task RollbackTransactionAsync(IDbTransaction tx) { await Task.CompletedTask; } public QueueTask? GetNextTask(IDbTransaction tx, string? taskType = null) { if (taskType == null) return GetNextTaskRolling(); QueueTask? task = null; if (_quesByType.TryGetValue(taskType, out var que)) { que.TryDequeue(out task); } return task; } public QueueTask? GetNextTaskRolling() { QueueTask? task = null; var topicsCount = _quesByType.Count; for (int i = 0; i < topicsCount; i++) { //todo: concurrent access if (i == _currentShard) { var keyValuePair = _quesByType.ToArray()[i]; var que = keyValuePair.Value; que.TryDequeue(out task); if (que.IsEmpty) { _quesByType.TryRemove(keyValuePair); } break; } } //todo: concurrent access _currentShard = _currentShard == topicsCount - 1 ? 0 : _currentShard + 1; return task; } public async Task GetNextTaskAsync(IDbTransaction tx, string? taskType = null) { if (taskType == null) return await Task.FromResult(GetNextTaskRolling()); QueueTask? task = null; if (_quesByType.TryGetValue(taskType, out var que)) { que.TryDequeue(out task); } return await Task.FromResult(task); } public void SaveTask(QueueTask task, IDbTransaction tx) { } public async Task SaveTaskAsync(QueueTask task, IDbTransaction tx) { await Task.CompletedTask; } }