How to set routing type ActiveMQ Artemis from client - activemq-artemis

I am trying to follow the hello world example. With regular ActiveMQ it works, but ActiveMQ Artemis is giving me headaches. I guess there is some configuration I am not doing correctly. The Address is made, but is it made using Multicast routing. I think I need Unicast (queue routing).
The below snippet does not work for the artemis version of ActiveMQ. Is it possible what I am trying to do? I would like to auto-create a durable Queue.
public class SimpleAmqpTest
{
[Fact]
public async Task TestHelloWorld()
{
Address address = new Address("amqp://guest:guest#localhost:5672");
Connection connection = await Connection.Factory.CreateAsync(address);
Session session = new Session(connection);
Message message = new Message("Hello AMQP");
var target = new Target
{
Address = "simple-queue",
Durable = 1,
};
SenderLink sender = new SenderLink(session, "sender-link", target, null);
await sender.SendAsync(message);
ReceiverLink receiver = new ReceiverLink(session, "receiver-link", "simple-queue");
message = await receiver.ReceiveAsync();
receiver.Accept(message);
await sender.CloseAsync();
await receiver.CloseAsync();
await session.CloseAsync();
await connection.CloseAsync();
}
}

Finally found out what I was doing wrong, as Amqp does not have the configuration of queues and topics, it can be defined in the Capabilities. For some reason Artemis creates topics by default (multicast). If you need AnyCast you can specify your need using Capabilities = new Symbol[] { new Symbol("queue") }. For the full test fact:
public async Task TestHelloWorld()
{
//strange, works using regular activeMQ and the amqp test broker from here: http://azure.github.io/amqpnetlite/articles/hello_amqp.html
//but this does not work in ActiveMQ Artemis
Address address = new Address("amqp://guest:guest#localhost:5672");
Connection connection = await Connection.Factory.CreateAsync(address);
Session session = new Session(connection);
Message message = new Message("Hello AMQP");
Target target = new Target
{
Address = "q1",
Capabilities = new Symbol[] { new Symbol("queue") }
};
SenderLink sender = new SenderLink(session, "sender-link", target, null);
sender.Send(message);
Source source = new Source
{
Address = "q1",
Capabilities = new Symbol[] { new Symbol("queue") }
};
ReceiverLink receiver = new ReceiverLink(session, "receiver-link", source, null);
message = await receiver.ReceiveAsync();
receiver.Accept(message);
await sender.CloseAsync();
await receiver.CloseAsync();
await session.CloseAsync();
await connection.CloseAsync();
}

Related

UWP DatagramsSocket doesn't not fire MessageReceived

I'm working on a UWP application which should communicate via TCP/UDP to a remote device. My issue is that the UWP app successfully sends UDP messages to the remote device, but does not receive the replies.
Here follows the code extracted from the app (simplified):
async Task TestUdpIP()
{
// Writer to the DatagramSocket
DataWriter writer;
using (var udpClient = new DatagramSocket())
{
try
{
// UDP Socket binding
udpClient.MessageReceived += UdpClient_MessageReceived;
var controllerName = new Windows.Networking.HostName(controllerIpAddress.ToString());
await udpClient.BindEndpointAsync(controllerName, controllerIpPort.ToString());
var remoteHostName = new Windows.Networking.HostName(hostIpAddres.ToString());
await udpClient.ConnectAsync(remoteHostName, remoteHostPort.ToString());
// Create a message to send
string message = "Some message";
// Reset the counter of messages received back from the remote robot
messagesReceived = 0;
// Send the message
writer = new DataWriter(udpClient.OutputStream);
writer.WriteString(message);
await writer.StoreAsync();
// Wait for robot status messages
await Task.Delay(5000);
}
catch
{
}
}
}
void UdpClient_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
// Just increment the number of messages received
messagesReceived++;
}
However the UdpClient_MessageReceived handler does not fire. I'm sure that UDP messages are correctly sent from the UWP app and that the remote device replies back as shown in the following screenshot from Wireshark (the test has been taken on the same PC where the UWP app is running)
.
(IP Address, Port) details are shown in the following list to better explain the picture above
UWP application: (192.168.1.108, 19000) to send and receive.
Remote device: (192.168.1.152, 15999) to receive and (192.168.1.152, 54697) to send
Note: this is a similar question, where the answer says that for whatever reason the DatagramSocket should fire some messages before being able to receive. In my example a message is sent out however the message received handler does not fire anyway.
Note: The UWP app has been granted the internet (client) and the internet (client and server) capabilities
Note: I've tried also this (more readable) approach to bind the inbound/outbound datagram socket on the UWP app obtaining the same results:
// UDP Socket binding
var controllerName = new HostName(controllerIpAddress.ToString());
var remoteHostName = new HostName(hostIpAddres.ToString());
EndpointPair endpointpar = new EndpointPair(controllerName,
controllerIpPort.ToString(),
remoteHostName,
remoteHostPort.ToString());
udpClient.MessageReceived += UdpClient_MessageReceived;
await udpClient.ConnectAsync(endpointpar);
Where is the issue? Many thanks!
Please try to also add the Private Networks (Client & Server) capability in your app's manifest.
On other hand, you can try the Official DatagramSocket sample to see whether the both devices can communicate with each other.
After some experimenting, I came out with the idea of using two different DatagramSocket instances: one to send out UDP messages, and one to listen for incoming messages. With this code, I've been able to send UDP messages to the remote device (as before) and also I've been able to receive UDP messages from the remote device.
async Task TestUdpIP_DifferentPorts()
{
// Writer to the DatagramSocket
DataWriter writer;
// Inbound and outbound DatagramSocket
DatagramSocket udpListener = new DatagramSocket();
DatagramSocket udpSender = new DatagramSocket();
try
{
// String containing the serializaed message
string serializedMessage = "Some message";
var controllerName = new HostName(controllerIpAddress.ToString());
var remoteHostName = new HostName(hostIpAddres.ToString());
// Bind listener
udpListener.MessageReceived += UdpClient_MessageReceived;
await udpListener.BindEndpointAsync(controllerName, controllerIpPort.ToString());
// Connect sender
await udpSender.ConnectAsync(remoteHostName, remoteHostPort.ToString());
// Reset the counter of messages received back from the remote robot
messagesReceived = 0;
// Send the message
writer = new DataWriter(udpSender.OutputStream);
writer.WriteString(JsonConvert.SerializeObject(message));
await writer.StoreAsync();
// Wait for robot status messages
await Task.Delay(1000);
}
catch (Exception ex)
{
// Some exception handling
}
udpSender.Dispose();
udpListener.Dispose();
}
void UdpClient_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
// Just increment the number of messages received
messagesReceived++;
}
With this approach only the IP port (or service name) of the inbound listener needs to be specified. The framework will choose the next available outbound IP port.
Note: If I understand well the DatagramSocket.ConnectAsync(EndpointPair) documentation, the same DatagramSocket instance can be used to send and listen for incoming message, so I could not figure out the need for two different instances. From the documentation:
This ConnectAsync(EndPointPair) method on a DatagramSocket is used to define the local and remote endpoint where datagrams will be sent when using the OutputStream property. This method also restricts remote IP addresses of packets that will be accepted to the remote hostname in the endpointPair parameter. Only incoming packets that match the remote endpoint in the endpointPair parameter will trigger the MessageReceived event on the DatagramSocket.

does kafka support dotnet core?

I'm trying to make a Kafka producer and consumer, but my project is in dotnet Core 2.0 and it doesn't seem to work well with kafka. This is the proof-of-concept I've tried coming up with. I'm using Visual Studio 2017 with the kafka-net nuget package:
using
using KafkaNet;
using KafkaNet.Model;
using KafkaNet.Protocol;
producer
static void Main(string[] args)
{
string payload = "Welcome to Kafka!";
string topic = "IDGTestTopic";
Message msg = new Message(payload);
Uri uri = new Uri("localhost:9092");
var options = new KafkaOptions(uri);
var router = new BrokerRouter(options);
var client = new Producer(router);
client.SendMessageAsync(topic, new List<Message> { msg }).Wait();
Console.ReadLine();
}
consumer
static void Main(string[] args)
{
string topic = "IDGTestTopic";
Uri uri = new Uri("http://localhost:9092");
var options = new KafkaOptions(uri);
var router = new BrokerRouter(options);
var consumer = new Consumer(new ConsumerOptions(topic, router));
foreach (var message in consumer.Consume())
{
Console.WriteLine(Encoding.UTF8.GetString(message.Value));
}
Console.ReadLine();
}
When I try to run the producer first, I get an error message on the BrokerRouter:
$exception {System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: port
at System.Net.IPEndPoint..ctor(IPAddress address, Int32 port)
at KafkaNet.DefaultKafkaConnectionFactory.Resolve(Uri kafkaAddress, IKafkaLog log)
at KafkaNet.Model.KafkaOptions.<get_KafkaServerEndpoints>d__0.MoveNext()
at KafkaNet.BrokerRouter..ctor(KafkaOptions kafkaOptions)
at SampleKafkaProducer.Program.Main(String[] args) in C:\v4target\SampleKafka\SampleKafkaProducer\SampleKafkaProducer\Program.cs:line 18} System.ArgumentOutOfRangeException
How is a port of 9092 out of range? My Visual Studio projects are running on ports in the 55000's. Multiple sources I've researched use 9092 as a kafka port.
Does anyone understand the error message? Is part of the main problem because I'm using a version of Kafka not compatible with dotnet core?
The problem is with the uri.
Uri uri = new Uri("localhost:9092");
If you print out the uri.Port, it's -1. Hence the ArgumentOutOfRangeException.
Try this instead:
Uri uri = new Uri("http://localhost:9092");
From the KafkaNet Repository. This is how they setup the URI:
var options = new KafkaOptions(new Uri("http://CSDKAFKA01:9092"), new Uri("http://CSDKAFKA02:9092"))
{
Log = new ConsoleLog()
};

MassTransit 3 How to send a message explicitly to the error queue

I'm using MassTransit with Reactive Extensions to stream messages from the queue in batches. Since the behaviour isn't the same as a normal consumer I need to be able to send a message to the error queue if it fails an x number of times.
I've looked through the MassTransit source code and posted on the google groups and can't find an anwser.
Is this available on the ConsumeContext interface? Or is this even possible?
Here is my code. I've removed some of it to make it simpler.
_busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(new Uri("rabbitmq://localhost/"), h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.UseInMemoryScheduler();
cfg.ReceiveEndpoint(host, "customer_update_queue", e =>
{
var _observer = new ObservableObserver<ConsumeContext<Customer>>();
_observer.Buffer(TimeSpan.FromMilliseconds(1000)).Subscribe(OnNext);
e.Observer(_observer);
});
});
private void OnNext(IList<ConsumeContext<Customer>> messages)
{
foreach (var consumeContext in messages)
{
Console.WriteLine("Content: " + consumeContext.Message.Content);
if (consumeContext.Message.RetryCount > 3)
{
// I want to be able to send to the error queue
consumeContext.SendToErrorQueue()
}
}
}
I've found a work around by using the RabbitMQ client mixed with MassTransit. Since I can't throw an exception when using an Observable and therefore no error queue is created. I create it manually using the RabbitMQ client like below.
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (IConnection connection = factory.CreateConnection())
{
using (IModel model = connection.CreateModel())
{
string exchangeName = "customer_update_queue_error";
string queueName = "customer_update_queue_error";
string routingKey = "";
model.ExchangeDeclare(exchangeName, ExchangeType.Fanout);
model.QueueDeclare(queueName, false, false, false, null);
model.QueueBind(queueName, exchangeName, routingKey);
}
}
The send part is to send it directly to the message queue if it fails an x amount of times like so.
consumeContext.Send(new Uri("rabbitmq://localhost/customer_update_queue_error"), consumeContext.Message);
Hopefully the batch feature will be implemented soon and I can use that instead.
https://github.com/MassTransit/MassTransit/issues/800

Is RESTEasy RegisterBuiltin.register necessary when using ClientResponse<T>

I am developing a REST client using JBOSS app server and RESTEasy 2.3.6. I've included the following line at the beginning of my code:
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
Here's the rest of the snippet:
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(host, port, AuthScope.ANY_REALM), new UsernamePasswordCredentials(userid,password));
ClientExecutor executor = createAuthenticatingExecutor(httpclient, host, port);
String uriTemplate = "http://myhost:8080/webapp/rest/MySearch";
ClientRequest request = new ClientRequest(uriTemplate, executor);
request.accept("application/json").queryParameter("query", searchArg);
ClientResponse<SearchResponse> response = null;
List<MyClass> values = null;
try
{
response = request.get(SearchResponse.class);
if (response.getResponseStatus().getStatusCode() != 200)
{
throw new Exception("REST GET failed");
}
SearchResponse searchResp = response.getEntity();
values = searchResp.getValue();
}
catch (ClientResponseFailure e)
{
log.error("REST call failed", e);
}
finally
{
response.releaseConnection();
}
private ClientExecutor createAuthenticatingExecutor(DefaultHttpClient client, String server, int port)
{
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
HttpHost targetHost = new HttpHost(server, port);
authCache.put(targetHost, basicAuth);
// Add AuthCache to the execution context
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);
// Create ClientExecutor.
ApacheHttpClient4Executor executor = new ApacheHttpClient4Executor(client, localContext);
return executor;
}
The above is a fairly simple client that employs the ClientRequest/ClientResponse<T> technique. This is documented here. The above code does work (only left out some trivial variable declarations like host and port). It is unclear to me from the JBOSS documentation as to whether I need to run RegisterBuiltin.register first. If I remove the line completely - my code still functions. Do I really need to include the register method call given the approach I have taken? The Docs say I need to run this once per VM. Secondly, if I am required to call it, is it safe to call more than one time in the same VM?
NOTE: I do understand there are newer versions of RESTEasy for JBOSS, we are not there yet.

How to access the keyspace notifications with ServiceStack.redis

I am trying to access the keyspace notifications in a .Net Application using ServiceStack.Redis. I am new to Redis.
I enabled event notifications on cache by command:
CONFIG SET notify-keyspace-events KEs
I am subscribing to the channel "key*:*" in .Net. The following is my code:
const string ChannelName = "__key*__:*";
using (var redisConsumer = new RedisClient("localhost:6379"))
using (var subscription = redisConsumer.CreateSubscription())
{
subscription.OnSubscribe = channel =>
{
Console.WriteLine(String.Format("Subscribed to '{0}'", channel));
};
subscription.OnUnSubscribe = channel =>
{
Console.WriteLine(String.Format("UnSubscribed from '{0}'", channel));
};
subscription.OnMessage = (channel, msg) =>
{
Console.WriteLine(String.Format("Received '{0}' from channel '{1}'",
msg, channel));
};
Console.WriteLine(String.Format("Started Listening On '{0}'", ChannelName));
subscription.SubscribeToChannels(ChannelName); //blocking
}
From another .Net application, I am adding new data to the cache. I am expecting to receive an event (in OnMessage). The application is not capturing any event, on adding a new item in cache.
But, when I run the command "psubscribe 'key*:*'" on redis-cli.exe, it captures the events properly. ( when I add a new item to cache, it displays the event details in a console window.)
I am unable to capture the same in my application. Am I missing anything here?
use subscription.SubscribeToChannelsMatching(ChannelName);