Как очистить/очистить объект AsyncLocal в BackgroundService(Microsoft.Hosting.Extensions.BackgroundService)?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как очистить/очистить объект AsyncLocal в BackgroundService(Microsoft.Hosting.Extensions.BackgroundService)?

Сообщение Anonymous »

У меня есть фоновая служба, которая выполняет некоторые задачи и задания в долго выполняющемся потоке. Для простоты мы будем рассматривать это как планировщик, который выполняет асинхронный вызов SQL и повторяет его. Теперь я использую AsyncLocal для хранения метаданных для целей регистрации в службе и хочу группировать каждое повторение задачи как транзакцию. Я полагал, что в отличие от веб-приложений BackgroundService будет иметь один объект AsyncLocal(ExecutionContext), который мне придется очищать после каждого повторения (каждого вызова SQL в этом примере). Что касается проблемы, я не могу очистить объект.
Вот реализация моего класса хранилища AsyncLocal.

Код: Выделить всё

 public class AsyncLocalStorage : ILocalStorage
{
private readonly AsyncLocal _context;
public AsyncLocalStorage()
{
_context = new AsyncLocal(OnValueChanged);
}

private static void OnValueChanged(AsyncLocalValueChangedArgs args)
{
Log("OnValueChanged! Prev: {0} ; Current: {1}", RuntimeHelpers.GetHashCode(args.PreviousValue), RuntimeHelpers.GetHashCode(args.CurrentValue));
}

public T GetData()
{
try
{
return _context.Value;
}
catch (Exception ex)
{
Log("Ex: " + ex.ToString());
}

return default(T);
}

public void SetData(T value)
{
_context.Value = value;
}

public void Clear()
{
_context.Value = default(T);
}
}
Здесь я устанавливаю свои метаданные для объекта AsyncLocal, а затем вызываю функцию Clear. Но экземпляр объекта остается. Я приложил журналы для дальнейшего использования.

Код: Выделить всё

02-05-2024 20:10:38 - [4:(DEBUG)] - [TName: ]TRANSACTION STARTED (The AsyncLocal Object is created and I assign my object "Transaction" using context.SetData())
02-05-2024 20:10:38 - [1:(ERROR)] - OnValueChanged! Prev: 0 ; Current: 5773521
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]The async SQL call is made.... (The Transaction object is modified context.GetData() . I guess the obj is passed to thread 9 )
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 0 ; Current: 5773521
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]---- random things are taken care off using the Transaction object that resulted in the following OnValueChanged logs .
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 0 ; Current: 5773521
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 5773521 ; Current: 0
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 5773521 ; Current: 0
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 0 ; Current: 5773521
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 5773521 ; Current: 0
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]The Async SQL call returned a Task object .
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 0 ; Current: 5773521
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]Processing of the metadata done on thread 4 is over.
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 5773521 ; Current: 0
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]Most of the processing on Thread 9 is also over and The Task returned by SQL call has finished.
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]Now the Transaction object is fetched with context.GetData() and is Loaded into a Thread Processor that runs independently using "ThreadPool.QueueWorkItem(Event, transaction) , which happens to be thread 10"
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 0 ; Current: 5773521
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]Everything seems to be over and its time to call context.Clear() //called.
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 5773521 ; Current: 0
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]Tried getting the transaction object here to verify using context.GetData(), returned null here.
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ProcessThread]Working with the transaction object reference in the Event thread.
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ProcessThread]Also working with the transaction object that is passed to this thread processor. Have no idea why the below log has occured.
02-05-2024 20:10:39 - [1:(ERROR)] - OnValueChanged! Prev: 5773521 ; Current: 0  (I am sure the transaction object goes out of scope here)
02-05-2024 20:10:39 - [4:(DEBUG)] - [TName: ]TRANSACTION STARTED (new repetition, calling the GetData function again before creating a new transaction object and assigning. I only assign a new object if it is null)
02-05-2024 20:10:40 - [1:(ERROR)] - OnValueChanged! Prev: 0 ; Current: 5773521
02-05-2024 20:10:40 - [4:(DEBUG)] - [TName: ] Suprise suprise!! it is not NULL. I have no idea why it isn't .
02-05-2024 20:10:40 - [4:(DEBUG)] - [TName: ]I have already cleared all the component objects in the transaction object . A New transaction object is needed here.
Почему это происходит? Есть ли что-то, что мне не хватает?
РЕДАКТИРОВАТЬ: Минимальный воспроизводимый пример приведен ниже. Я постарался сделать его маленьким

Код: Выделить всё

public class Worker : BackgroundService
{
private readonly ILogger _logger;
private readonly BackgroundTask _backgroundtask;

public Worker(ILogger logger, BackgroundTask task)
{
_logger = logger;
_backgroundtask = task;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
_backgroundtask.MakeTask();
await Task.Delay(1000, stoppingToken);
}
}
}

public sealed class BackgroundTask
{
private readonly ILogger _logger;

public BackgroundTask(ILogger logger)
{
_logger = logger;
}

public void MakeTask()
{
Transactions trans = TransactionService.GetCurrentTransaction();

if(trans == null)
{
Console.WriteLine("[T:] There is no TransactionObject", Thread.CurrentThread.ManagedThreadId);
trans = TransactionService.GetOrCreateTransaction();
}
else
{
Console.WriteLine("[T:] There is a Transaction Object", Thread.CurrentThread.ManagedThreadId);
}

trans.PrintTransactionName();

Task.Run(() =>
{
trans.SetTransactionName("transaction2");
trans.PrintTransactionName();

trans.ClearEverything();
});
}
}

public class TransactionService
{
private static AsyncLocalStorage transactionContext;

static TransactionService()
{
transactionContext = new AsyncLocalStorage();
}

public static Transactions GetCurrentTransaction()
{
return transactionContext.GetData();
}

public static Transactions GetOrCreateTransaction()
{
var transaction = GetCurrentTransaction();
if (transaction == null)
{
transaction = new Transactions("Transaction1");
transactionContext.SetData(transaction);
}
return transaction;
}

public static void RemoveOutstandingTransactions()
{
transactionContext.Clear();
}
}

public class Transactions
{
private string transactionName;
public Transactions(string trans)
{
transactionName = trans;
}

public void SetTransactionName(string trans)
{
transactionName = trans;
}

public void PrintTransactionName()
{
if (!string.IsNullOrEmpty(transactionName))
{
Console.WriteLine("[T:] The transactionName is {1}", Thread.CurrentThread.ManagedThreadId, transactionName);
}
}

public void ClearEverything()
{
transactionName = null;
Console.WriteLine("[T:] The Transaction Object is being cleared", Thread.CurrentThread.ManagedThreadId);
TransactionService.RemoveOutstandingTransactions();

// Just checking if the object is cleared in this thread.

if(TransactionService.GetCurrentTransaction() == null)
{
Console.WriteLine("[T:] The Transaction Object is null after clearing", Thread.CurrentThread.ManagedThreadId);
}
}
}
Создайте рабочую службу с ядром .NET, как показано в приведенном выше примере.
Почему в начале следующего повторения после очистки объекта AsyncLocal появляется объект транзакции. Журналы будут выглядеть примерно так...

Код: Выделить всё

[T:] There is no TransactionObject
[T:] OnValueChanged! Prev: 0 ; Current: 72766
[T:] The transactionName is Transaction1
[T:] OnValueChanged! Prev: 0 ; Current: 72766
[T:] The transactionName is transaction2
[T:] OnValueChanged! Prev: 72766 ; Current: 0
[T:] The Transaction Object is being cleared
[T:] OnValueChanged! Prev: 72766 ; Current: 0
[T:] The Transaction Object is null after clearing

[T:] There is a Transaction Object
[T:] OnValueChanged! Prev: 72766 ; Current: 0
[T:] OnValueChanged! Prev: 0 ; Current: 72766
[T:] The transactionName is transaction2
[T:] The Transaction Object is being cleared
[T:] OnValueChanged! Prev: 72766 ; Current: 0
[T:] The Transaction Object is null after clearing
[T:] OnValueChanged! Prev: 0 ; Current: 72766
И почему хеш объекта одинаковый?

Подробнее здесь: https://stackoverflow.com/questions/784 ... emicrosoft
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»