I asked a question in:
Microservice Architecture dependency which pattern to use when using a clustered Microservice architecure.
I recieved answer that point to point should work but when reading:
https://nats.io/documentation/concepts/nats-req-rep/
It feels like all subscribers recieves event (and because of that handles it) but there will just be one subscriber that responses. This will not work when putting an order event that will trigger an update-inventory-event that Inventory microservices subscribes to (as in example in link) i.e it wont work in a clustered env due to inventory will be updated the same amount of times as the amount of microservice instances.
How can I solve this scenario using Nats?
Thanks in advance!
NATS.io supports this feature using queue groups:
All subscriptions with the same queue name will form a queue group.
Each message will be delivered to only one subscriber per queue group,
using queuing semantics. You can have as many queue groups as you wish.
Normal subscribers will continue to work as expected.
Connect your services using the queue group (sample is node.js):
https://github.com/nats-io/node-nats#queue-groups
nats.subscribe('foo', {'queue':'job.workers'}, function() {
received += 1;
});
then the client would use the library provided request methods:
https://github.com/nats-io/node-nats#basic-usage
// Request for single response with timeout.
nats.requestOne('help', null, {}, 1000, function(response) {
// `NATS` is the library.
if(response.code && response.code === NATS.REQ_TIMEOUT) {
console.log('Request for help timed out.');
return;
}
console.log('Got a response for help: ' + response);
});
Related
First of all, I have a server stream method. In the method, I will request an actor in a loop. I expect that after each request is responded, the application will return the result to the caller. But no, I found that it still waits for all responses to be completed before returning, is this normal?
// The code is as follows, for the convenience of observing the results, I added sleep
override def itKeepsReplying(in: HelloRequest): Source[HelloReply, NotUsed] = {
Source(1 to 10).map(index => {
Thread.sleep(5000)
HelloReply(character.toString)
})
}
In order to confirm whether grpc itself supports, I tried java's implementation of this piece,
If you want to send data to the caller: responseObserver.onNext(responseBuilder.build());,
If you want to end this call: responseObserver.onCompleted(); ,
Data is sent to the caller every time onNext is called.
So my question is:
Is my assumption correct? If akka-grpc can do it
If it can be done, please give an example
I’m writing functionality for receiving messages from Azure Service Bus Topic and delete the specified message from Topic. Before deleting that message, I need to send that message to other Topic.
static async Task ProcessMessagesAsync(Message message, CancellationToken token)
{
// Process the message.
Console.WriteLine($"Received message: WorkOrderNumber:{message.MessageId} SequenceNumber:{message.SystemProperties.SequenceNumber} Body:{Encoding.UTF8.GetString(message.Body)}");
Console.WriteLine("Enter the WorkOrder Number you want to delete:");
string WorkOrderNubmer = Console.ReadLine();
if (message.MessageId == WorkOrderNubmer)
{
//TODO:Post message into other topic(Priority) then delete from this current topic.
var status=await SendMessageToBus(message);
if (status == true)
{
await normalSubscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
Console.WriteLine($"Successfully deleted your message from Topic:{NormalTopicName}-WorkOrderNumber:" + message.MessageId);
}
else
{
Console.WriteLine($"Failed to send message to PriorityTopic:{PriorityTopicName}-WorkOrderNumber:" + message.MessageId);
}
}
else
{
Console.WriteLine($"Failed to delete your message from Topic:{NormalTopicName}-WorkOrderNumber:" + WorkOrderNubmer);
// Complete the message so that it is not received again.
// This can be done only if the subscriptionClient is created in ReceiveMode.PeekLock mode (which is the default).
await normalSubscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
// Note: Use the cancellationToken passed as necessary to determine if the subscriptionClient has already been closed.
// If subscriptionClient has already been closed, you can choose to not call CompleteAsync() or AbandonAsync() etc.
// to avoid unnecessary exceptions.
}
}
My issue with this approach is:
It’s not scalable; what if the message is the 50th in the collection? We’d have to iterate through 49 times and mark i.e deleted.
It’s a long-running process.
To avoid these problems, I want to get the specified message from the queue based on Index or sequence number then I can delete that from the topic.
So, can anyone suggest me how to resolve this problem?
So if I understand your questions and comments correctly you are trying to do something like this:
Incoming messages come into either a standard topic or priority
topic.
Some process checks messages in the standard topic and
"moves" them to the priority topic based on some criteria by
deleting them from the standard topic and adding them to the
priority topic.
Messages are processed as normal.
As Sean noted, step 2 simply won't work. Service Bus is a first=in-first-out-ish system where a consumer simply picks up the next available message. You can sort through a queue by pulling out all the messages and abandoning/completing them based on specific criteria, but scaling is a problem. In addition, you can think of each topic subscription as its own separate queue- removing a message form one subscription does not remove it from any of the other subscriptions.
What I would suggest instead of trying to pull out everything from the topics and then putting back the ones you want to keep, add a sorting queue in front of the two topics. If you don't need to sort the high priority messages you could put this sorting process in front of the standard priority topic only.
This is how the process would work:
Incoming messages are added to a sorting queue Note that this is a single queue, not a topic. At this point in the process we want to ensure there is only one copy of each message.
A sorting process moves messages from the sorting queue into either the standard or priority queue as is appropriate. Using something like Azure Functions you can scale this process fairly easily.
Messages are processed from the topics as normal.
Having the following code on the server:
Meteor.publish(null, function(){
// Return some cursors.
})
will according to the documentation have the following effect: the record set is automatically sent to all connected clients.
How can I on the client side determine if all the documents published by this function has been received? If I would use a subscription instead, it would provide me with a ready callback, letting me know when all the documents been received. What's the matching way here? Or are the documents already received at the client when my client side code starts to execute?
I'm afraid there's no way to have a ready callback for so called universal subscriptions you mentioned above. Just have a look at this part of Meteor's code, where the publish and subscription logic is defined on the server. For convenience I'm copy/pasting the code below:
ready: function () {
var self = this;
if (self._isDeactivated())
return;
if (!self._subscriptionId)
return; // unnecessary but ignored for universal sub
if (!self._ready) {
self._session.sendReady([self._subscriptionId]);
self._ready = true;
}
}
The _subscriptionId is only given to named subscriptions, which are those that you would manually define using Meteor.subscribe method. The subscriptions corresponding to null publish functions, doesn't have their own _subscriptionId, so as you can see from the code above, the server is not event trying to send the ready message to the client.
I'm kind of new to web development and I became a fan of meteor because of the way it lets me do cool stuf really easy. I have been toying around with the parties example and I have added a date attribute for the parties. I would like to only subscribe the client to parties that have not yet expired.
Essentially where datenow < partydate.
I find myself stuck in writing the correct subscribe code as I only find documentation on how to subscribe based on database attributes and not based on comparing the date of the party with the current date.
Meteor.subscribe("parties"); --> I think this is the part of the code on the client that I need to edit.
I really hope somebody could show me in the right direction on writing the correct subscribe code.
The client subscribes to what the server is willing to send to them.
if(Meteor.isClient){
Meteor.subscribe("parties");
}
The server filters data the client shouldn't have, typically for security reasons. You wouldn't want passwords or private information being published. Any client can open up the console and browse the full data set that was published to them.
if(Meteor.isServer){
Meteor.publish("parties", function(){
return Parties.find({date: {$gt: Date.now()}});
});
}
If you want clients to be able to see both expired parties and non-expired parties, you would publish the whole set from the server, then filter it on the client in a template helper.
if(Meteor.isServer){
Meteor.publish("parties", function(){
return Parties.find();
});
}
if(Meteor.isClient){
Meteor.subscribe("parties");
Template.templateName.allParties = function(){
return Parties.find();
}
Template.templateName.activeParties = function(){
return Parties.find({date: {$gt: Date.now()}});
}
}
Can I create a new conference room (Asterisk ConfBridge) through Asterisk Manager Interface (AMI)? Help me please!
This response is for anyone who has struggled as me to do this, even if the first response and the comments to it may be enough.
So, you can originate a conference call, with the action Originate and the application ConfBridge (as far as i know, it comes with Asterisk, not independent).
You can see all the available fields here http://www.voip-info.org/wiki/view/Asterisk+Manager+API+Action+Originate
I will throw an example without every field, but the ones I know and needed on my app.
This is what you throw at the Asterisk Manager Interface, if you want to call someone into a conference, then add someone else (without the comments ofc.)
Action: Originate // The action type
ActionID: CreateConf-1 // This id will be linked to further events about the action
Channel: SIP/1001 // The sipId of the peer u wanna call
Timeout: 30000 // If he doesnt respons in 30000ms, drop it
CallerID: Asterisk // The id of the caller (will be seen on target phone)
Application: ConfBridge // The application
Async: true // (NOT SURE, MAYBE BULLSHIT) If false, i think you can no longer originate while he hasn't answered
Data: 1234 // Very important, this is like the conference id, will detail above
Action: Originate
ActionID: CreateConf
Channel: SIP/1000
Timeout: 30000
CallerID: Asterisk
Application: ConfBridge
Async: true
Data: 1234
So with this, one block at time, two guys will be called into a conference.
As you saw the Data field represents the identifier of the call, so if you wanna give your conference an id, use it. This way you could create and manage different conferences.
Since i work with NAMI (the nodejs library for Asterisk Manager Interface) (https://github.com/marcelog/Nami), let me also drop you how to do thanks to the lib.
var namiLib = require('nami');
var namiInstance = new (namiLib.Nami)(config); // See more about config (and everything else about nami) in their docs
namiInstance.open();
var action = new namiLib.Actions.Originate();
action.channel = 'SIP/1000';
action.data = '12345'; // my conferenceId
action.timeout = 30000;
action.callerID = 'Metisse\'s king';
action.application = 'ConfBridge';
action.async = true;
namiInstance.send(action, function (response) {
// deal with the response
});
Obviously, if you need to use NAMI to have control other Asterisk, you have to do something more generic to handle sending your actions and validating them, also watching for errors.
You can use dynamic conference(without room exist) feature and create calls using Originate command to application Confbridge.
No. You can use an AMI redirect to transfer your call to a piece of dialplan code that would read a channel variable, database look up or some other mechanism to set up a new conference, however.
For a full list of AMI actions for ConfBridge, please see: https://wiki.asterisk.org/wiki/display/AST/ConfBridge+10#ConfBridge10-ConfBridgeAsteriskManagerInterface(AMI)Actions