mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-26 01:25:42 -05:00
Re-enable parallel message processing (#1741)
* add flag to handler * cleanup * concurrency control * add flag for handler setters * update service flags * fix event handlers * more handlers * make sure behavior is unchanged if flag is off * cleanup * add test case for parallel processing * comments * stop dispatcher in test * add log for request lifespan * cleanup and add comments * correctly release semaphore * remove deleted file from merge * use await for semaphore release * move handler invocation to await and adjust test * cleanup exception handling and wrapper * space * loose assertion condition to make test stable
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Channel;
|
||||
@@ -84,5 +86,70 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging
|
||||
Assert.True(handlerCalled);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParallelMessageProcessingTest()
|
||||
{
|
||||
int numOfRequests = 10;
|
||||
int msForEachRequest = 1000;
|
||||
// Without parallel processing, this should take around numOfRequests * msForEachRequest ms to finish.
|
||||
// With parallel process, this should take around 1 * msForEachRequest ms to finish.
|
||||
// The diff should be around (numOfRequests - 1) * msForEachRequest ms.
|
||||
// In order to make this test stable, we loose the assertion by checking the diff against
|
||||
// (numOfRequests / 2) * msForEachRequest ms, which should for sure pass.
|
||||
Assert.IsTrue(GetTimeToHandleRequests(false, numOfRequests, msForEachRequest) - GetTimeToHandleRequests(true, numOfRequests, msForEachRequest) > msForEachRequest * (numOfRequests / 2));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time to handle certain amount of requests in ms
|
||||
/// </summary>
|
||||
/// <param name="parallelMessageProcessing">Wheater to enable parallel processing</param>
|
||||
/// <param name="numOfRequests">num of requests to handle</param>
|
||||
/// <param name="msForEachRequest">rough time taken to finish each reqeust in ms</param>
|
||||
/// <returns></returns>
|
||||
private long GetTimeToHandleRequests(bool parallelMessageProcessing, int numOfRequests, int msForEachRequest)
|
||||
{
|
||||
RequestType<int, int> requestType = RequestType<int, int>.Create("test/requestType");
|
||||
var mockChannel = new Mock<ChannelBase>();
|
||||
SemaphoreSlim unfinishedRequestCount = new SemaphoreSlim(numOfRequests);
|
||||
bool okayToEnd = false;
|
||||
mockChannel.Setup(c => c.MessageReader.ReadMessage())
|
||||
.Returns(Task.FromResult(Message.Request("1", "test/requestType", null)));
|
||||
var dispatcher = new MessageDispatcher(mockChannel.Object);
|
||||
dispatcher.ParallelMessageProcessing = parallelMessageProcessing;
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
var handler = async (int _, RequestContext<int> _) =>
|
||||
{
|
||||
// simulate a slow sync call
|
||||
Thread.Sleep(msForEachRequest / 2);
|
||||
// simulate a delay async call
|
||||
await Task.Delay(msForEachRequest / 2);
|
||||
await unfinishedRequestCount.WaitAsync();
|
||||
if (unfinishedRequestCount.CurrentCount == 0)
|
||||
{
|
||||
// cut off when we reach numOfRequests
|
||||
stopwatch.Stop();
|
||||
okayToEnd = true;
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
};
|
||||
|
||||
dispatcher.SetRequestHandler(requestType, handler, false, true);
|
||||
dispatcher.Start();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (okayToEnd)
|
||||
{
|
||||
// wait until we finish handling the required amount of requests
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
dispatcher.Stop();
|
||||
return stopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user