public Task<HttpResponseMessage> EnqueueTask(string commandDescription, IGraphClient client, IExecutionPolicy policy, CypherQuery query)
{
// grab the endpoint in the same thread
var txBaseEndpoint = policy.BaseEndpoint;
var serializedQuery = policy.SerializeRequest(query);
CustomHeaders = query.CustomHeaders;
var task = new Task<HttpResponseMessage>(() =>
Request.With(client.ExecutionConfiguration, query.CustomHeaders, query.MaxExecutionTime)
.Post(Endpoint ?? txBaseEndpoint)
.WithJsonContent(serializedQuery)
// HttpStatusCode.Created may be returned when emitting the first query on a transaction
.WithExpectedStatusCodes(HttpStatusCode.OK, HttpStatusCode.Created)
.ExecuteAsync(
commandDescription,
responseTask =>
{
// we need to check for errors returned by the transaction. The difference with a normal REST cypher
// query is that the errors are embedded within the result object, instead of having a 400 bad request
// status code.
var response = responseTask.Result;
policy.AfterExecution(TransactionHttpUtils.GetMetadataFromResponse(response), this);
return response;
})
.Result
);
_taskQueue.Add(task, _cancellationTokenSource.Token);
if (_consumer == null)
{
_consumer = () =>
{
while (true)
{
try
{
Task queuedTask;
if (!_taskQueue.TryTake(out queuedTask, 0, _cancellationTokenSource.Token))
{
// no items to consume
_consumer = null;
break;
}
queuedTask.RunSynchronously();
}
catch (InvalidOperationException)
{
// we are done, CompleteAdding has been called
break;
}
catch (OperationCanceledException)
{
// we are done, we were canceled
break;
}
}
};
_consumer.BeginInvoke(null, null);
}
return task;
}