Using Sessions in synchronous Request-Response patterns - session

I am trying to get sessions to work in the following architecture.
Multiple heterogenous worker roles that monitor and process requests from queue1, and send their responses to queue2.
One front web role, which receives requests from outside via REST or SOAP, submits them into queue1, and waits for a response from queue2. Once it's received, the response is returned to the caller.
The web role is there to leverage scalability and allow the worker roles to be created dynamically when the load is too high (which is why the entire Ruth Goldberg machine, there is no way without the service bus).
I am using a call to:
MessageSession sess = myQueueClient.AcceptMessageSession(mySessionId, TimeSpan.FromSeconds(timeoutPerSec));
which is followed by:
BrokeredMessage bm = sess.Receive();
and the call to AcceptMessageSession crashes and burns with the exception:
BR0012A sessionful message receiver cannot be created on an entity that does not require sessions. Ensure RequiresSession is set to true when creating a Queue or Subscription to enable sessionful behavior.
Now I do set RequiresSession to true:
if (!_queueManager.QueueExists(clientID))
_queueManager.CreateQueue(clientID).RequiresSession = true;
else
_queueManager.GetQueue(clientID).RequiresSession = true;
but it does not help.
What am I doing wrong?

You have to create a queue with RequiresSession set to true in QueueDescription when you create a queue, not in a QueueDescription of already created queue.
So you in your case queue creation should look similar to this:
if (!_queueManager.QueueExists(clientID))
{
QueueDescription queueDescription = new QueueDescription(clientID)
{
RequiresSession = true
};
_queueManager.CreateQueue(queueDescription);
}

Related

Laravel API check if client http connection is still alive

In Laravel we have an api endpoint that may take a few minutes. It's processing an input in batches and giving a response when all batches are processed. Pseudo-code below.
Sometimes it takes too long for the user, so the user navigates away and the connection is killed client-side. However, the backend processing still continues until the backend tries to return the response with a broken pipe error.
To save ressources, we're looking for a way to check after each batch if the client is still connected with a function like check_if_client_is_still_connected() below. If not, an error is raised and processing is stopped. Is there a way to achieve this ?
function myAPIEndpoint($all_batches){
$result = [];
for ($batch in $all_batches) {
$batch_result = do_something_long($batch);
$result = $result + $batch_result;
check_if_client_is_still_connected();
}
return result;
}
PS: I know async tasks or web sockets could be more appropriate for long requests, but we have good reasons to use a standard http endpoint for this.

Test for an active service worker from within the client

From within my client.js, I register a service worker with:
var someVariable;
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('./service-worker.js')
.then(function() {
console.log('Service worker registered.');
if(localStorage.someVariable) {
someVariable = JSON.parse(localStorage.someVariable);
};
});
};
Now, further down my client.js code, I would like to check whether client.js has an active service worker up and running.
Doing so from within service-worker.js would somewhat correspond to testing for self.registration, as self.registration.active does not seem to work.
However, what would be the equivalent test for an active service worker from within client.js?
navigator.serviceWorker.ready retuns a Promise, but I do not know if this is really what I need for use in/as a conditional.
Your options
If you want to check whether the current page is under the control of some service worker at the current moment, you can examine navigator.serviceWorker.controller. It will be null if the current page is not controlled by a service worker, and set to a ServiceWorker instance if it is controlled by one.
If you want to check if the service worker associated with a given ServiceWorkerRegistration is active at a given point in time, you can do that with code like:
const registration = await navigator.serviceWorker.register('sw.js');
// Examine `registration.active` to see if, at the current point in time,
// there's an active service worker.
If you want to write code that will wait until there's any active service worker associated with the current page's service worker registration, then await navigator.serviceWorker.ready will do that for you.
active vs. controlling
Just a quick note on the difference between an active service worker, and a controlling service worker. A service worker can be active but not in control of any client pages—this is what would happen the first time a service worker is registered for a given scope if the service worker doesn't call clients.claim().
If you are calling clients.claim() in your service worker, then the distinction between active and controlling can mostly be ignored.

MassTransit RequestClient timeout handling

I have tried several scenario to handle timeouts in request, but they dont seem to work.
I have passed the timeout TimeSpan when both creating the request client and/or creating the request. The request does not recive a response during the time span configured, but the task continue executing and seems hanging and no RequestTimeoutException is thrown.
What is the exact solution for handling clients timeout.
EDIT
The use case leading to the timeout is when the whole consumer service is down, so the initial request is not consumed at all. Folowing the code exemple of the request. As mentioned, i tried to pass the RequestTimeout also in the client creation. Other than this, it works perfectly when all parts are running.
var client = _busControl.CreateRequestClient<CheckRequest>(new Uri($"{rabbitHostUri}/CheckQueue"));
var response = await client.GetResponse<CheckResponse>(checkRequest, timeout: RequestTimeout.After(s: 60)).ConfigureAwait(false);
var checkResponse = response.Message;

masstransit deferred respond in sagas

I am investigating using sagas in mass transit to orchestrate activities across several services. The lifetime of the saga is short - less than 2 seconds if all goes well.
For my use case, i would like to use the request/respond approach, whereby the client requests a command, the saga handles that command, goes through some state changes as messages are received and eventually responds to the first command that initiated the saga, at which point the client receives the response and can display the result of the saga.
From what i can see, by this point, the context is no longer aware of the initial request. How can I reply to a message that was received in this way? Is there something i can persist to the saga data when handling the first event, and use that to reply later on?
Thanks Alexey. I have realised that I can store the ResponseAddress and RequestId from the original message on the saga, and then construct a Send() later on.
Getting the response details from the original request
MassTransit.EntityFrameworkIntegration.Saga.EntityFramework
SagaConsumeContext<TSagaData, TMessage> payload;
if (ctx.TryGetPayload(out payload))
{
ResponseAddress = payload.ResponseAddress;
RequestId = payload.RequestId ;
}
Sending the response
var responseEndpoint = await ctx.GetSendEndpoint(responseAddress);
await responseEndpoint.Send(message, c => c.RequestId = requestId);
UPDATE: The documentation has been updated to include a more complete example.
Currently, the saga state machine can only do immediate response like this:
// client
var response = await client.Request(requestMessage);
// saga
During(SomeState,
When(RequestReceived)
.Then(...)
.Respond(c => MakeResponseMessage(c))
.TransitionTo(Whatever)
)
So you can respond when handling a request.
If you want to respond to something you received before, you will have to craft the request/response conversation yourself. I mean that you will have to have decoupled response, so you need to send a message and have a full-blown consumer for the reply message. This will be completely asynchronous business.

Azure, SubscriptionClient.OnMessage, and Sessions

Does the Azure Service Bus Subscription client support the ability to use OnMessage Action when the subscription requires a session?
I have a subscription, called "TestSubscription". It requires a sessionId and contains multipart data that is tied together by a SessionId.
if (!namespaceManager.SubscriptionExists("TestTopic", "Export"))
{
var testRule = new RuleDescription
{
Filter = new SqlFilter(#"(Action='Export')"),
Name = "Export"
};
var subDesc = new SubscriptionDescription("DataCollectionTopic", "Export")
{
RequiresSession = true
};
namespaceManager.CreateSubscription(sub`enter code here`Desc, testRule);
}
In a seperate project, I have a Service Bus Monitor and WorkerRole, and in the Worker Role, I have a SubscriptionClient, called "testSubscriptionClient":
testSubscriptionClient = SubscriptionClient.CreateFromConnectionString(connectionString, _topicName, CloudConfigurationManager.GetSetting("testSubscription"), ReceiveMode.PeekLock);
I would then like to have OnMessage triggered when new items are placed in the service bus queue:
testSubscriptionClient.OnMessage(PersistData);
However I get the following message when I run the code:
InvalidOperationException: It is not possible for an entity that requires sessions to create a non-sessionful message receiver
I am using Azure SDK v2.8.
Is what I am looking to do possible? Are there specific settings that I need to make in my service bus monitor, subscription client, or elsewhere that would let me retrieve messages from the subscription in this manner. As a side note, this approach works perfectly in other cases that I have in which I am not using sessioned data.
Can you try this code:
var messageSession=testSubscriptionClient.AcceptMessageSession();
messageSession.OnMessage(PersistData);
beside of this:
testSubscriptionClient.OnMessage(PersistData);
Edit:
Also, you can register your handler to handle sessions (RegisterSessionHandler). It will fire your handle every new action.
I think this is more suitable for your problem.
He shows both way, in this article. It's for queue, but I think you can apply this to topic also.

Resources