2014-06-28 12 views
8

Sto cercando di trovare un modo per mantenere una traccia sui compiti asincroni flusso di esecuzione in un modo che sarebbe stato facile capire quanto riguarda compito, qual è stato il flusso originale che ha avviato esso.Monitoraggio C# /. NET compiti flusso

mi serve principalmente per la registrazione, il debugging e conservando una sorta di stack per uno specifico flusso di esecuzione.

per esempio: se ho server con molti clienti provenienti da più indirizzi IP e la necessità di server per eseguire un flusso di lavoro per ogni cliente che coinvolge molte azioni asincrone quindi coinvolge molti compiti diversi per ogni flusso di esecuzione; la registrazione di un tale flusso è difficile, specialmente quando si utilizza il meccanismo asincrono/attesa.

Non ho trovato un modo per racchiudere le attività in un modo che per ogni attività eseguita conoscerei la descrizione del flusso iniziale durante la registrazione, ad esempio se avvio un nuovo flusso di attività per un'azione con descrizione - "Manutenzione del cliente 10.0.3.4" Voglio essere in grado di aggiungere questa descrizione per ogni voce di registro che esce da questo flusso in tutta l'operazione che ha creato da essa.

Quando si utilizzano le discussioni solo la sua facile perché avete variabili statiche filo. con compiti è impossibile ... Ho anche cercato di creare il mio task scheduler che vi avvolgerà qualsiasi operazione che lo utilizza (anche quando si utilizza async/attendere metodi), ma ha ottenuto in un vicolo cieco perché la base task scheduler a volte utilizza nuovo thread (anche se non vi era alcuna richiesta implicita di utilizzare un nuovo thread) - il metodo "TryExecuteTaskInline" può talvolta essere eseguito in un nuovo thread.

Qualsiasi idea o suggerimento su come posso raggiungere questo obiettivo?

+1

Che ne dici di mostrarci del codice con quello che stai cercando di fare? –

risposta

11

È possibile utilizzare Trace.CorrelationManager.ActivityId per memorizzare un ID operazione logico, o anche meglio memorizzare uno ImmutableStack di ID operazioni logiche. E 'conservato nel CallContext e viene copiato con il metodo async chiama:

public static class LogicalFlow 
{ 
    private static readonly string _name = typeof (LogicalFlow).Name; 

    private static ImmutableStack<Guid> LogicalStack 
    { 
     get 
     { 
      return CallContext.LogicalGetData(_name) as ImmutableStack<Guid> ?? ImmutableStack.Create<Guid>(); 
     } 
     set 
     { 
      CallContext.LogicalSetData(_name, value); 
     } 
    } 

    public static Guid CurrentId 
    { 
     get 
     { 
      var logicalStack = LogicalStack; 
      return logicalStack.IsEmpty ? Guid.Empty : logicalStack.Peek(); 
     } 
    } 
} 

è possibile utilizzarlo come un IDisposable in modo da poter utilizzare un ambito using per assicurarsi che ci sia un Pop ad ogni Push:

private static readonly Popper _popper = new Popper(); 

public static IDisposable StartScope() 
{ 
    LogicalStack = LogicalStack.Push(Guid.NewGuid()); 
    return _popper; 
} 

private sealed class Popper : IDisposable 
{ 
    public void Dispose() 
    { 
     LogicalStack = LogicalStack.Pop(); 
    } 
} 

Usage:

using (LogicalFlow.StartScope()) 
{ 
    Console.WriteLine(LogicalFlow.CurrentId); 
    await DoSomethingAsync(); 
    Console.WriteLine(LogicalFlow.CurrentId); 
} 

Questa risposta precedentemente invocato Trace.CorrelationManager.LogicalOperationStack ma Is LogicalOperationStack incompatible with async in .Net 4.5

+0

Grazie è la soluzione che ho cercato :) Ti accennerò solo che puoi spingere in questo stack altri oggetti e non solo Guids – ThaPhoeniX

+1

Questo è vero ... Ma assicurati di spingere solo tipi immutabili. – i3arnon

+0

@ i3arnon: capisco cosa intendi. Ora capisco l'intero problema. – drowa

2

Con le attività, è possibile memorizzare questo tipo di informazioni nel execution context. Here's an example come farlo usando il contesto della chiamata logica, che è un tipo di contesto di esecuzione. Trace.CorrelationManager si basa anche sul contesto di esecuzione.