2014-06-28 13 views
8

Tôi đang cố gắng tìm một cách để theo dõi luồng thực thi nhiệm vụ không đồng bộ theo cách dễ hiểu về tác vụ, luồng gốc ban đầu là gì.Theo dõi C# /. NET nhiệm vụ dòng chảy

Tôi cần nó chủ yếu để ghi nhật ký, gỡ lỗi và bảo quản một loại dấu vết ngăn xếp cho một luồng thực thi cụ thể. Ví dụ:

ví dụ: nếu tôi có máy chủ có nhiều khách hàng từ nhiều IP và máy chủ cần thực hiện luồng công việc cho từng khách hàng. việc ghi nhật ký như vậy là rất khó, đặc biệt là khi sử dụng cơ chế không đồng bộ/chờ đợi.

Tôi chưa tìm ra cách để bọc các tác vụ theo cách mà mỗi tác vụ được thực thi tôi sẽ biết mô tả luồng ban đầu khi ghi nhật ký, ví dụ nếu tôi bắt đầu một luồng công việc mới cho một hành động mô tả - "Chăm sóc khách hàng 10.0.3.4" tôi muốn có thể thêm mô tả này cho từng mục nhật ký xuất phát từ luồng này trong bất kỳ tác vụ nào được tạo từ nó.

Khi chỉ sử dụng đề tài dễ dàng vì bạn có biến tĩnh tĩnh. với các nhiệm vụ không thể của nó ... Tôi thậm chí đã cố gắng tạo ra công cụ lập lịch nhiệm vụ của riêng mình, sẽ loại bỏ bất kỳ tác vụ nào sử dụng nó (ngay cả khi sử dụng các phương thức async/await) nhưng đã bị chết vì cơ sở lập lịch tác vụ đôi khi sử dụng chuỗi mới (mặc dù không có bất kỳ yêu cầu ngầm nào để sử dụng một chuỗi mới) - phương thức "TryExecuteTaskInline" đôi khi có thể chạy trong một chuỗi mới.

Bất kỳ ý tưởng hoặc đề xuất nào về cách tôi có thể đạt được điều đó?

+1

Làm thế nào để hiển thị cho chúng tôi một số mã với những gì bạn đang cố gắng làm? –

Trả lời

11

Bạn có thể sử dụng Trace.CorrelationManager.ActivityId để lưu trữ id hoạt động hợp lý hoặc thậm chí lưu trữ tốt hơn ImmutableStack id hoạt động hợp lý. Nó được lưu trữ trong CallContext và được sao chép qua các phương pháp async gọi:

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(); 
     } 
    } 
} 

Bạn có thể sử dụng nó như một IDisposable vì vậy bạn có thể sử dụng một phạm vi using để đảm bảo có một Pop cho mọi 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(); 
    } 
} 

Cách sử dụng:

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

Câu trả lời này trước đây dựa vào Trace.CorrelationManager.LogicalOperationStack nhưng Is LogicalOperationStack incompatible with async in .Net 4.5

+0

Cảm ơn đó là giải pháp tôi đã tìm kiếm :) Tôi sẽ chỉ đề cập đến việc bạn có thể đẩy vào ngăn xếp các đối tượng khác chứ không chỉ Guids – ThaPhoeniX

+1

Đó là sự thật ... Nhưng hãy chắc chắn rằng bạn chỉ đẩy các loại bất biến. – i3arnon

+0

@ i3arnon: Tôi hiểu ý của bạn là gì. Bây giờ tôi hiểu toàn bộ vấn đề. – drowa

2

Với công việc, bạn có thể lưu trữ loại thông tin này trong execution context. Here's an example cách thực hiện bằng ngữ cảnh cuộc gọi logic, đó là một loại bối cảnh thực thi. Trace.CorrelationManager cũng được xây dựng trên bối cảnh thực thi.

Các vấn đề liên quan