2016-07-10 7 views
2

У меня есть одна конечная точка API, которая должна как можно скорее вернуться к вызывающему. В настоящее время он возвращает менее 1 мс. Если, однако, я записываю некоторые данные в базу данных, теперь он приближается к 10 мс.Обработка после завершения запроса

Как вы подходите к завершению запроса и затем выполняете какую-либо обработку после завершения запроса? Я попытался с Response.Body.Flush(), но это не завершает запрос, и он все еще занимает полные 10 мс. Похоже, что он отправляет/очищает полезную нагрузку, но запрос все еще не завершается до тех пор, пока не будет завершен метод действия.

Будет ли это работать для ведения журнала в промежуточном программном обеспечении?

EDIT:

Один из способов, который я нашел, чтобы использовать FluentScheduler так:

JobManager.Initialize(new Registry()); 
JobManager.Start(); 

в Program.cs перед тем host.Run(), а затем планировать непосредственное задание от действий, как это :

JobManager.AddJob(() => 
{ 
    // do something... 
}, (s) => s.ToRunOnceIn(1).Seconds()); 
+1

Это немного к широкому, не зная, используете ли вы брокеров/автобусов сообщений или видите конкретный код. Возможно, опубликуйте какой-то код того, что вы используете. Самый простой способ - использовать шину сообщений и просто запустить событие и позже зарегистрировать его. – Tseng

+0

Я не использую какую-либо систему очередей. Я надеюсь, что в этом есть что-то, что можно поддержать. – pbz

+0

Response.OnCompleted близок, но соединение остается открытым, когда оно работает. – pbz

ответ

2

Вам нужно как-то начать новую тему. Промежуточное программное обеспечение, установленное перед конвейером, даст вам возможность выполнить работу непосредственно перед завершением запроса. Если вы вращаете нить, оттуда, то это может сработать.

Возможно, вы захотите использовать своего рода producer-consumer pattern, чтобы вы не убивали ваш сервер. В противном случае, если каждый запрос запускает поток, который работает немедленно, и у вас много запросов одновременно, у вас может закончиться нехватка ресурсов. Потребитель-производитель поможет вам разобраться в этой работе.

Если вы не спешите, вы можете подождать еще неделю или около того, когда я доставлю регистратор файлов для ASP.NET, а затем вы увидите аналогичную реализацию.

+0

Разве вы, ребята из Microsoft, не сказали нам не начинать свои собственные потоки в ASP.NET (предположим, что это должно относиться и к ASP.NET Core), потому что это путается с тем, как ASP.NET управляет пулом потоков для передачи асинхронные запросы? – Tseng

+0

Если вы используете потребителя-производителя, вам не нужно будет вращать новые потоки для каждого запроса. –

+0

Такие структуры, как Quarts.NET, FluentScheduler и HangFire, работают, начиная с потоков. Тем не менее, они не поддерживают Core только от того, что я могу сказать. – pbz

1

Вход в пО промежуточного слоя не поможет, так как вы все равно будете в трубопроводе запроса и вы можете или не может иметь необходимую информацию запишите, что вам нужно сделать.

Вы можете войти асинхронно, который, вероятно, даст вам самое большое улучшение без существенных архитектурных изменений: Async Programming : Introduction to Async/Await on ASP.NET

Если это не работает, вы можете сделать что-то, что многопоточный. Это становится более сложным, но он по-прежнему возможен: Multithreading in C# .NET 4.5 (Part 1)

+0

Я надеялся, что будет «крючок» для «после завершения конвейера» ... Response.OnCompleted приближается, но подключенный все еще открыт, и вызывающая сторона все еще ждет, чтобы я сделал обработку в OnCompleted. – pbz

+0

Я думаю, что проблема, с которой вы столкнетесь в этом подходе, состоит в том, что она все еще является частью конвейера, а это означает, что это замедлит ваш общий ответ. Я не думаю, что это действительно купило бы вам что-нибудь, если вы не представили какие-либо асинхронные или многопоточные методы. – MichaelDotKnox

+0

Если я могу подключиться к конвейеру ПОСЛЕ завершения запроса, то есть после того, как вызывающий API получит полный ответ, то с точки зрения внешнего мира это будет выглядеть так, как будто запрос занял менее 1 мс. Да, если сервер находится под большим давлением, общий коэффициент будет увеличиваться с 1 мс, но эти случаи редки. В большинстве случаев процессорные ядра ничего не делают. – pbz

0

Async - это правильный способ решить эту проблему. Во время вашего запроса (когда захотите) запустите асинхронное соединение/запрос к базе данных. Просто не ждите, пока он закончит.

+0

В ASP.NET Core используется инъекция зависимостей, а некоторые службы охвачены областью действия, что означает, что у них есть только срок службы, который равен одному из запросов и будет удален в конце. Я не знаю, как это работает с реализацией 'ILogger '. Вы ** определенно ** это не охвачено? В противном случае это решение не будет работать, так как есть вероятность, что он будет удален до его завершения (если запрос значительно быстрее, чем операции регистрации) – Tseng

+0

К сожалению, это должно было быть комментарий к другому ответу. Хорошая точка зрения, однако, я не рассматривал взаимодействия с такими ресурсами. –

0

Это просто мысль, так что не голосуйте, если я уйду. Не могли бы вы использовать HttpResponse.RegisterForDispose()? Например:

public class JobToRunAfterRequestIsComplete : IDisposable { 
    public void Dispose() 
    { 
     // Do your post-processing here. 
    } 
} 

public class YourController { 
    public void YourAction() { 
     // Do your normal processing here 
     ... 
     // Register your post processing here 
     this.Response.RegisterForDispose(new JobToRunAfterRequestIsComplete()); 
    } 
} 
Смежные вопросы