2012-09-30 41 views
9

Tôi đang tạo thư viện Ghi nhật ký lưu trữ mọi thứ trên bảng Azure. Viết vào bảng đó rõ ràng là mất rất nhiều thời gian (không bao giờ hơn 1 giây, nhưng nó vẫn còn quá nhiều điều để làm cho sự chờ đợi người dùng), vì vậy phương pháp Log trả về một trường hợp LogResult, đây là lớpNgăn IIS thực hiện nhiệm vụ trước khi kết thúc

public class LogResult 
{ 
    public string Id { get; set; } 
    public Task LoggingTask { get; set; } 

    public LogResult(string id, Task task) 
    { 
     Id = id; 
     LoggingTask = task; 
    } 
} 

Và đây là cách thức phương thức Đăng nhập kết thúc

return new LogResult(id, Task.Factory.StartNew(() => 
    DoLogInAzure(account, id, exception, request)) 
); 

Để cung cấp cho người gọi tùy chọn chờ đợi hoàn thành (nếu đó là ứng dụng bảng điều khiển). Vấn đề tôi phải đối mặt là IIS không nên chờ cho nó trước khi trả lại cho người dùng phản hồi ... và nếu tôi không chờ đợi, IIS không luôn thực hiện nhiệm vụ. Ý tưởng là để hiển thị cho người dùng một thông báo "... Nếu bạn liên hệ với chúng tôi, hãy chắc chắn đề cập đến số vấn đề của bạn, XXX" và không làm cho anh ta đợi cho đến khi mục nhập nhật ký được viết.

Có cách nào để buộc IIS đợi cho đến khi tác vụ kết thúc, ngay cả sau khi nó trả về phản hồi? Tôi nghĩ rằng tôi có thể cần phải mã một dịch vụ Windows mà có yêu cầu không đồng bộ, nhưng nó trông giống như rất nhiều công việc chỉ để thêm một mục đăng nhập ... đặc biệt nếu tôi có thể lực lượng IIS chờ đợi cho nó.

Cảm ơn mọi ý tưởng!

+0

Tôi đã nghe rằng IIS khởi động lại 'trang web' chiếm quá nhiều bộ nhớ ... –

+0

Tôi hiểu :) tuy nhiên, tôi không nghĩ đó là trường hợp của tôi, như thể tôi đợi nhiệm vụ kết thúc, IIS hoàn thành thực thi và mục nhật ký được viết 100% số lần – g3rv4

+0

Như một giải pháp thay thế, bạn có thể sử dụng hàng đợi xanh để đăng nhập. Sau đó, một trình xử lý tin nhắn riêng biệt có thể ghi một cách không đồng bộ vào bảng màu xanh. Tốt hơn, nếu bạn nhận được một lỗi xử lý tin nhắn vẫn còn trên hàng đợi và sẽ được xử lý lại sau. –

Trả lời

8

Nhờ Damian Schenkelman và bài đăng trên blog của Phil Haack, tôi đã tìm ra vấn đề và giải pháp. Vấn đề là IIS reuses các chủ đề khi nó cần để xử lý các yêu cầu mới. Và vì nó không biết rằng nhiệm vụ của tôi là làm một số công việc, nó reuses thread (mà làm cho tinh thần). Sau đó, tôi chỉ cần thông báo cho IIS rằng tôi đang sử dụng thread đó và nó không thể được tái sử dụng (vì vậy, nó phải sử dụng lại một luồng khác, tạo một luồng mới hoặc đợi nó). Tôi đã sử dụng TaskFactory của riêng mình để xử lý việc tạo nhiệm vụ và tự động đăng ký một trình thông báo trong IIS. Để hoàn chỉnh, để giúp một số dân tộc khác với cùng một vấn đề như tôi, và để đọc gợi ý khác, đây là những gì tôi đã thực hiện

public class IISNotifier : IRegisteredObject 
{ 
    public void Stop(bool immediate) 
    { 
     // do nothing, I only run tasks if I know that they won't 
     // take more than a few seconds. 
    } 

    public void Started() 
    { 
     HostingEnvironment.RegisterObject(this); 
    } 

    public void Finished() 
    { 
     HostingEnvironment.UnregisterObject(this); 
    } 
} 

Và sau đó

public class IISTaskFactory 
{ 
    public static Task StartNew(Action act) 
    { 
     IISNotifier notif = new IISNotifier(); 
     notif.Started(); 
     return Task.Factory.StartNew(() => { 
      act.Invoke(); 
      notif.Finished(); 
     }); 
    } 
} 

Bây giờ, khi tôi muốn bắt đầu một nhiệm vụ log tôi chỉ làm

return new LogResult(id, IISTaskFactory.StartNew(() => 
    DoLogInAzure(account, id, exception, request)) 
); 

Bạn có thể nhìn thấy (và tải về code) tại https://github.com/gmc-dev/IISTask

11

This post từ Phil Hack nói về các tác vụ nền đang chạy trong ứng dụng ASP.NET.

+0

Tôi vừa đọc xong bài viết đó ... Cảm ơn, nó thực sự là thứ tôi cần. Tuy nhiên, nó không giải thích tại sao nhiệm vụ của tôi không phải lúc nào cũng được thực hiện ... Tôi đang chạy nó trên máy tính của mình và tạo ra 100 ngoại lệ trong một cửa hàng phút khoảng 92 nếu tôi không đợi nhiệm vụ hoàn thành. Hồ bơi ứng dụng không được khởi động lại ... Điều đó thậm chí có ý nghĩa không? – g3rv4

+0

Bạn tạo ra các ngoại lệ như thế nào? Khi bạn chờ, bạn chỉ cần cố định chuỗi đang chạy cho đến khi tất cả Tác vụ hoàn tất, nhưng điều đó không cần thiết nếu quá trình này vẫn đang chạy. Quá trình có dừng lại trước khi các tác vụ thực sự chạy không? Sử dụng logic giả lập (ví dụ: in ấn để gỡ lỗi cửa sổ) trong mỗi tác vụ để đảm bảo rằng tất cả các tác vụ đều có thời gian để bắt đầu và hoàn thành. –

+0

Ngoại lệ tôi xử lý ngay bây giờ, là b/c Tôi đang gán null vào một chuỗi không có giá trị null trên một thực thể ... sau đó, 'context.SaveChanges();' không thành công. Tuy nhiên, nếu tôi tạo ra một ngoại lệ và không làm bất cứ điều gì khác, nó luôn luôn được lưu trữ. Cách để làm cho nó thất bại là tạo ra rất nhiều ngoại lệ trong một khoảng thời gian ngắn. Tôi đoán rằng IIS có thể tái sử dụng thread để xử lý các yêu cầu mới, và đó là khi nhiệm vụ của tôi bị hủy bỏ. Tôi đang làm 100 yêu cầu (mà ném một ngoại lệ) trong vòng chưa đầy 10 giây, và đó là khi nó không thành công. – g3rv4

0

Thông tin không đủ nhưng tôi nghi ngờ nó có thể liên quan đến GC và tài liệu tham khảo nếu nó hoạt động khi bạn đợi tác vụ. Với mục đích của bạn, một cách tốt hơn là sử dụng ETW (EventProvider) và đặt ActivityId cho mỗi yêu cầu. Đơn giản chỉ cần cấu hình một phiên ETW có thể chuyển hướng tất cả các tin nhắn vào một tập tin. Bạn có thể hiển thị ActivityId (Hướng dẫn) cho người dùng cuối.

+2

'Tác vụ' sẽ chạy tốt ngay cả khi không có tham chiếu đến nó, đó không phải là vấn đề. – svick

+0

Để kiểm tra xem đó có phải là vấn đề hay không, tôi đã lưu trữ tất cả các tham chiếu đến 'Task' trong một cá thể đơn lẻ ... tuy nhiên, điều đó không thay đổi hành vi của nó ... cho tác vụ trước khi phản hồi được truy xuất – g3rv4

0

Xin lỗi vì không thêm điều này làm bình luận, tôi không có đủ đại diện.

https://msdn.microsoft.com/en-us/library/system.web.hosting.iregisteredobject(v=vs.110).aspx

Ứng dụng có thể chỉ có một thể hiện của một loại đăng ký.

Điều này dường như cho thấy câu trả lời được chấp nhận của Gervasio Marchand có phần không chính xác, vì mỗi lệnh gọi phương thức trợ giúp tĩnh của mình đều tạo một IISNotifier mới, là một IRegisteredObject.

+1

bạn có thể tìm thấy ví dụ mà giải pháp này không hoạt động không? Tôi rất thích nhìn thấy một cái gì đó như thế, như tôi đã sử dụng cách tiếp cận này trên tấn của dự án và không bao giờ thấy bất cứ điều gì lạ – g3rv4

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