MassTransit and event versus command publishing - masstransit

I'm new to MassTransit, and I miss something in my understanding.
Let's say I have a server farm were all nodes can do the same job. The application framework is CQRS's styled. That means I have two base kind of message to publish :
Commands : must be handled by exactly one of the server, any of them (the first with job slot free)
Events : must be handled by all servers
I've have build an extremely simple MassTransit prototype (a console application that is sending hello every X seconds).
In the API, I can see there is a "publish" method. How can I specify what kind of message it is (one versus all server)?
If I look a the "handler" configuration, I can specify the queue uri. If I specify the same queue for all hosts, all hosts will get the message, but I cannot limit the execution to only one server.
If I listen from a host dedicated queue, only one server will handle the messages, but I don't know how to broadcast the other kind of message.
Please help me to understand what I'm missing.
PS: if it cares, my messaging system is rabbitmq.
In order to test, I have create a common class library with this classes :
public static class ActualProgram
{
private static readonly CancellationTokenSource g_Shutdown = new CancellationTokenSource();
private static readonly Random g_Random = new Random();
public static void ActualMain(int delay, int instanceName)
{
Thread.Sleep(delay);
SetupBus(instanceName);
Task.Factory.StartNew(PublishRandomMessage, g_Shutdown.Token);
Console.WriteLine("Press enter at any time to exit");
Console.ReadLine();
g_Shutdown.Cancel();
Bus.Shutdown();
}
private static void PublishRandomMessage()
{
Bus.Instance.Publish(new Message
{
Id = g_Random.Next(),
Body = "Some message",
Sender = Assembly.GetEntryAssembly().GetName().Name
});
if (!g_Shutdown.IsCancellationRequested)
{
Thread.Sleep(g_Random.Next(500, 10000));
Task.Factory.StartNew(PublishRandomMessage, g_Shutdown.Token);
}
}
private static void SetupBus(int instanceName)
{
Bus.Initialize(sbc =>
{
sbc.UseRabbitMqRouting();
sbc.ReceiveFrom("rabbitmq://localhost/simple" + instanceName);
sbc.Subscribe(subs =>
{
subs.Handler<Message>(MessageHandled);
});
});
}
private static void MessageHandled(Message msg)
{
ConsoleColor color = ConsoleColor.Red;
switch (msg.Sender)
{
case "test_app1":
color = ConsoleColor.Green;
break;
case "test_app2":
color = ConsoleColor.Blue;
break;
case "test_app3":
color = ConsoleColor.Yellow;
break;
}
Console.ForegroundColor = color;
Console.WriteLine(msg.ToString());
Console.ResetColor();
}
private static void MessageConsumed(Message msg)
{
Console.WriteLine(msg.ToString());
}
}
public class Message
{
public long Id { get; set; }
public string Sender { get; set; }
public string Body { get; set; }
public override string ToString()
{
return string.Format("[{0}] {1} : {2}" + Environment.NewLine, Id, Sender, Body);
}
}
I have also 3 console applications that just run the ActualMain method :
internal class Program
{
private static void Main(string[] args)
{
ActualProgram.ActualMain(0, 1);
}
}

What you want is known as Competing Consumers (search SO for that you'll find more info)
Using RabbitMQ makes life easy, all you need to do is specify the same queue name for each consumer you start, the message will be processed by only one of them.
Instead of generating a unique queue each time as you are doing.
private static void SetupBus(int instanceName)
{
Bus.Initialize(sbc =>
{
sbc.UseRabbitMqRouting();
sbc.ReceiveFrom("rabbitmq://localhost/Commands);
sbc.Subscribe(subs =>
{
subs.Handler<Message>(MessageHandled);
});
});
}
AFAIK, you'll need to have a separate process for command handlers as opposed to event handlers. All the command handlers will ReceiveFrom the same queue, all event handlers will ReceiveFrom their own unique queue.
The other piece of the puzzle is how you get messages into the bus. You can still use publish for commands, but if you have configured consumers incorrectly you could get multiple executions as the message will go to all consumers, if you want to guarantee the message ends up on a single queue you can use Send rather than Publish.
Bus.Instance
.GetEndpoint(new Uri("rabbitmq://localhost/Commands"))
.Send(new Message
{
Id = g_Random.Next(),
Body = "Some message",
Sender = Assembly.GetEntryAssembly().GetName().Name
});

Related

I want to connect the Spring application with the external bukkit server through the REST API method

I want to control the bukkit server through the spring web application.
For example, send a command to the console, receive his response, etc
I'm trying to figure out a way, but I can't find a good one.
How shall I do it?
Even if third-party plugins are imported through the database, I want to find a way to do basic bukkit control.
First, you need to decide how to send the request to the server. It seems to me that in your case, the easiest is run the built-in java web server (HttpServer) to receive commands, and then process them.
If you need synchronous actions, then you can always do callSyncMethod
To receive command output, simply create your own implementation of CommandSender with overridden sendMessage methods
For example, how do command execution endpoint
JavaPlugin plugin = /** get plugin **/;
HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 8001), 0);
server.createContext("/executeCommand", exchange -> {
if (!exchange.getRequestMethod().equals("POST")) {
exchange.getResponseBody().write("Method not supported".getBytes(StandardCharsets.UTF_8));
return;
}
// In this example body is command
String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
StringBuilder builder = new StringBuilder();
// You also need override many another methods to compile code,but just leave it empty
CommandSender sender = new CommandSender() {
#Override
public void sendMessage(#NotNull String message) {
builder.append(message);
}
#Override
public void sendMessage(#NotNull String... messages) {
for (String message : messages) {
builder.append(message + "\n");
}
}
#Override
public boolean isOp() {
return true;
}
#Override
public boolean hasPermission(#NotNull String name) {
return true;
}
#Override
public #NotNull String getName() {
return "WebServerExecutor";
}
};
// Waiting command execute finish
Bukkit.getScheduler().callSyncMethod(plugin, () -> Bukkit.dispatchCommand(sender, body)).get();
byte[] response = builder.toString().getBytes(StandardCharsets.UTF_8);
exchange.getResponseBody().write(response);
});
server.start()

Uni wait for Vertx eventBus message

I have two endpoints:
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/waitForEvent")
public Uni<Object> waitForEvent() {
return Uni.createFrom().emitter(em -> {
//wait for event from eventBus
// eventBus.consumer("test", msg -> {
// System.out.printf("receive event: %s\n", msg.body());
// em.complete(msg);
// });
}).ifNoItem().after(Duration.ofSeconds(5)).failWith(new RuntimeException("timeout"));
}
#GET
#Path("/send")
public void test() {
System.out.println("send event");
eventBus.send("test", "send test event");
}
The waitForEvent() should only complete if it receives the event from the eventBus. How can I achieve this using vertx and mutiny?
In general, we avoid that kind of pattern and use the request/reply mechanism from the event bus:
#GET
#Path("/send")
public Uni<String> test() {
return bus.<String>request("test", name)
.onItem().transform(Message::body)
.ifNoItem().after(Duration.ofSeconds(5)).failWith(new RuntimeException("timeout"));
}
When implementing with two endpoints (as in the question), it can become a bit more complicated as if you have multiple calls to the /waitForEvent endpoint, you need to be sure that every "consumer" get the message.
It is still possible, but would will need something like this:
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/waitForEvent")
public Uni<String> waitForEvent() {
return Uni.createFrom().emitter(emitter -> {
MessageConsumer<String> consumer = bus.consumer("test");
consumer.handler(m -> {
emitter.complete(m.body());
consumer.unregisterAndForget();
})
.ifNoItem().after(Duration.ofSeconds(5)).failWith(new RuntimeException("timeout"));
}
#GET
#Path("/send")
public void test() {
bus.publish("test", "send test event");
}
Be sure to use the io.vertx.mutiny.core.eventbus.EventBus variant of the event bus.

How to retrieve the value from the event listener from another class in java?

I have a program to get the values from a Bar code scanner(using jssc library) and it returns value as expected using event listener but I need to access that value from another class.
I tried to instantiate BarcodeScanner class to main method (ProcessTicket class) and called scannerHandler method and also called the getter method of model class to retrieve value but the getter method runs before the scan is completed. Could you please help me to achieve this?
public class BarcodeScanner {
public static Object SerialPortReader;
static SerialPort serialPort;
public void scannerHandler() {
serialPort = new SerialPort("COM4");
try{
serialPort.openPort();//Open serial port
//Set params. Also set params by this string:
serialPort.setParams(9600, 8, 1, 0);
serialPort.setParams(9600, 8, 1, 0);
serialPort.writeString(new String(new byte[]{0x02})); //triggers barcode scanner
serialPort.addEventListener(new SerialPortReader());//Add SerialPortEventListenerS
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
public static class SerialPortReader implements SerialPortEventListener {
String str;
String value;
public void serialEvent(SerialPortEvent event) {
if (event.isRXCHAR() && event.getEventValue() > 0) {//If data is available
//Check bytes count in the input buffer
try {
byte[] bytesCont = serialPort.readBytes(14);
str = new String(bytesCont);
ModelClass modelClass = new ModelClass();
modelClass.setBarcodeValue(str);
} catch (SerialPortException e) {
e.printStackTrace();
}
}
}
My ProcessTicket.java Class
public class ProcessTicket {
public static void main(String[] args) throws SQLException, SerialPortException {
BarcodeScanner bSC = new BarcodeScanner();
bSC.scannerHandler();
BarcodeScanner.SerialPortReader portReader = new BarcodeScanner.SerialPortReader();
ModelClass modelClass = new ModelClass();
String value = modelClass.getBarcodeValue();
System.out.println(value);
}
}
The main problem here is that you're treating an inherently asynchronous operation (reading from an external sensor in the real world) as if it's synchronous.
I simulated that external sensor stuff to make a standalone app that tests your business logic:
HowToRetrieveTheValueFromTheEventListenerFromAnotherClassInJava.java
package com.stackoverflow;
/**
* https://stackoverflow.com/questions/57452205/how-to-retrieve-the-value-from-the-event-listener-from-another-class-in-java
*/
public class HowToRetrieveTheValueFromTheEventListenerFromAnotherClassInJava {
public static void main(String[] args) {
BarcodeScanner barcodeScanner = new BarcodeScanner((String barcode) -> {
System.out.println("Barcode scanned: " + barcode);
});
barcodeScanner.startScan();
MockUser.startScanningStuffLol();
}
}
That call to MockUser.startScanningStuffLol() is only necessary because I'm testing this just in code, without using a real barcode scanner. Please don't focus on it. I'll post its implementation if you ask, but otherwise I'm assuming that your OS/Java/hardware are working the way they were designed to work, and you can just test this with those tools instead of my MockUser software simulation.
Here are the rest of the classes that you need to implement this:
BarcodeScannedCallback.java
package com.stackoverflow;
public interface BarcodeScannedCallback {
void callback(String barcode);
}
Since we're dealing with an asynchronous operation, we can't just start it and then check for a return value, like we would with a synchronous operation. Instead, we need to pass in a function that will be called once the operation is complete, and just wait for it to finish. BarcodeScannedCallback is the signature of that function (in other words, a description of how that function needs to be structured). It takes one string parameter, and returns nothing.
The implementation of BarcodeScannedCallback is this function that I've already mentioned above, which I'm passing into the BarcodeScanner constructor:
(String barcode) -> {
System.out.println("Barcode scanned: " + barcode);
}
As you can see, this function takes one string parameter, and returns nothing. So, it's an implementation of the BarcodeScannedCallback interface.
Now for the last class: the one that bridges our main method and the serial port, using the above interface.
BarcodeScanner.java
package com.stackoverflow;
public class BarcodeScanner implements SerialPortEventListener {
private SerialPort serialPort;
private final BarcodeScannedCallback callback;
public void startScan() {
try {
serialPort = new SerialPort("COM4");
serialPort.openPort();
serialPort.addEventListener(this);
// Also you can set params by this string: serialPort.setParams(9600, 8, 1, 0);
serialPort.setParams(9600, 8, 1, 0);
// Triggers barcode scanner.
serialPort.writeString(new String(new byte[]{0x02}));
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
#Override
public void serialEvent(SerialPortEvent event) {
boolean isDataAvailable = event.isRXCHAR() && event.getEventValue() > 0;
if (isDataAvailable) {
try {
byte[] bytesCont = serialPort.readBytes(14);
String barcode = new String(bytesCont);
callback.callback(barcode);
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
public BarcodeScanner(BarcodeScannedCallback callback) {
this.callback = callback;
}
}
So here's the full lifecycle of these events:
You create a BarcodeScanner.
You tell the BarcodeScanner, via the implementation of BarcodeScannedCallback that you pass into its constructor, what code to run once it receives a barcode over the serial port.
You call startScan on the BarcodeScanner, which opens the serial port and starts waiting for the user to scan a barcode.
The user scans a barcode. This data is transmitted over the serial port. The operating system's implementation of SerialPort calls BarcodeScanner.serialEvent.
Your implementation of serialEvent does its validations, pulls the data from the serial port and converts it from bytes to a string, and calls the BarcodeScannedCallback function that was passed in at the beginning.
When I run this (with my MockUser class setting up a background thread that "scans" a barcode every 3 seconds), I get this output:
Barcode scanned: 420L0L
Barcode scanned: 007
Barcode scanned: 12345
In your case, you should be able to scan 3 barcodes with your real-world barcode scanner, and get the same results.
Note that you may need to do something to keep the main method's thread from ending prematurely, depending on the context that you're running this in.
If you're running it in an Android app or a web server, those frameworks keep their main thread running indefinitely, until you kill the app/server.
But if you're running it as a custom command-line app (which it seems like you're doing, based on the existence of a main method), you will need to do something to keep it alive until you decide to kill it. The simplest way is to put an infinite loop like while (true); on the last line of your main method.

Sending scheduled emails by Web API using background tasks

I have researched too much about the ways for sending scheduled emails by .NET core Web API using background tasks. I know it's better that I should implement the background tasks in a windows service which runs separately with app domain.
But my requirement is from web client I will have a table with each row is a promotion event for customer, I can choose to active, pause, stop for each of them, then it will make call to API and from here.
I have to implement each background tasks for each of them that can run synchronous. I have to do that by Web API because end users don't have a place to host the service.
Actual solution:
After one day I came up with the solution which is using IHostedService with BlockingCollection to control the background tasks in runtime as below:
Code for background task using IHostedService:
namespace SimCard.API.Worker
{
internal class TimedHostedService : IHostedService, IDisposable
{
private CancellationTokenSource _tokenSource;
private readonly ILogger _logger;
private Timer _timer;
private readonly TasksToRun tasks;
private readonly IEmailService emailService;
public TimedHostedService(ILogger<TimedHostedService> logger, TasksToRun tasks, IEmailService emailService)
{
this.emailService = emailService;
this.tasks = tasks;
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
tasks.Dequeue();
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
emailService.SendEmail("ptkhuong96#gmail.com", "Test", "OK, Done now");
_logger.LogInformation("Mail sent!");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
}
Here is the code for BlockingCollection:
namespace SimCard.API.Worker
{
public class TasksToRun : ITasksToRun
{
private readonly BlockingCollection<int> _tasks;
public TasksToRun() => _tasks = new BlockingCollection<int>();
public void Enqueue(int settings) => _tasks.Add(settings);
public void Dequeue() => _tasks.Take();
}
}
And the code in controller with get called from web client:
[HttpPost("/api/worker/start")]
public IActionResult Run()
{
tasks.Enqueue(15);
return Ok();
}
Code for Startup.cs:
services.AddHostedService<TimedHostedService>();
services.AddSingleton<TasksToRun, TasksToRun>();
Issue:
After click active button for the first event => controller will get called and one instance of this background task will run. How to pause that task and resume it?
If the first issue is solved, how can I create each background task for each event in the table, think about I may could create more and more event in the future, how can one event get actived, stopped, paused, resumed without affect to another one?
I'm really stuck with this requirement and don't know how to proceed further. If you have a different approach that can adapt my case, you could recommend me also.
Thank you very much for your support.

How to exit clean from WebAPI background service

The code below is a Web API that prints on behalf of a SPA. For brevity I've omitted using statements and the actual printing logic. That stuff all works fine. The point of interest is refactoring of the printing logic onto a background thread, with the web api method enqueuing a job. I did this because print jobs sent in quick succession were interfering with each other with only the last job printing.
It solves the problem of serialising print jobs but raises the question of how to detect shutdown and signal the loop to terminate.
namespace WebPrint.Controllers
{
public class LabelController : ApiController
{
static readonly ConcurrentQueue<PrintJob> queue = new ConcurrentQueue<PrintJob>();
static bool running = true;
static LabelController()
{
ThreadPool.QueueUserWorkItem((state) => {
while (running)
{
Thread.Sleep(30);
if (queue.TryDequeue(out PrintJob job))
{
this.Print(job);
}
}
});
}
public void Post([FromBody]PrintJob job)
{
queue.Enqueue(job);
}
}
public class PrintJob
{
public string url { get; set; }
public string html { get; set; }
public string printer { get; set; }
}
}
Given the way I acquire a thread to servicing the print queue, it is almost certainly marked as a background thread and should terminate when the app pool tries to exit, but I am not certain of this, and so I ask you, dear readers, for your collective notion of best practice in such a scenario.
Well, I did ask for best practice.
Nevertheless, I don't have long-running background tasks, I have short-running tasks. They arrive asynchronously on different threads, but must be executed serially and on a single thread because the WinForms printing methods are designed for STA threading.
Matt Lethargic's point about possible job loss is certainly a consideration, but for this case it doesn't matter. Jobs are never queued for more than a few seconds and loss would merely prompt operator retry.
For that matter, using a message queue doesn't solve the problem of "what if someone shuts it down while it's being used" it merely moves it to another piece of software. A lot of message queues aren't persistent, and you wouldn't believe the number of times I've seen someone use MSMQ to solve this problem and then fail to configure it for persistence.
This has been very interesting.
http://thecodelesscode.com/case/156
I would look at your architecture at a higher level, doing 'long running tasks' such as printing should probably live outside of you webapi process entirely.
If this we myself I would:
Create a windows service (or what have you) that has all the printing logic in it, the job of the controller is then to just talk to the service either by http or some kind of queue MSMQ, RabbitMQ, ServiceBus etc.
If via http then the service should internally queue up the print jobs and return 200/201 to the controller as soon as possible (before printing happens) so that the controller can return to the client efficiently and release it's resources.
If via a queuing technology then the controller should place a message on the queue and again return 200/201 as quick as possible, the service can then read the messages at it's own rate and print one at a time.
Doing it this way removes overhead from your api and also the possibility of losing print jobs in the case of a failure in the webapi (if the api crashes any background threads may/will be effected). Also what if you do a deployment at the point of someone printing, there's a high chance the print job will fail.
My 2 cents worth
I believe that the desired behavior is not something that should be done within a Controller.
public interface IPrintAgent {
void Enqueue(PrintJob job);
void Cancel();
}
The above abstraction can be implemented and injected into the controller using the frameworks IDependencyResolver
public class LabelController : ApiController {
private IPrintAgent agent;
public LabelController(IPrintAgent agent) {
this.agent = agent;
}
[HttpPost]
public IHttpActionResult Post([FromBody]PrintJob job) {
if (ModelState.IsValid) {
agent.Enqueue(job);
return Ok();
}
return BadRequest(ModelState);
}
}
The sole job of the controller in the above scenario is to queue the job.
Now with that aspect out of the way I will focus on the main part of the question.
As already mentioned by others, there are many ways to achieve the desired behavior
A simple in memory implementation can look like
public class DefaultPrintAgent : IPrintAgent {
static readonly ConcurrentQueue<PrintJob> queue = new ConcurrentQueue<PrintJob>();
static object syncLock = new Object();
static bool idle = true;
static CancellationTokenSource cts = new CancellationTokenSource();
static DefaultPrintAgent() {
checkQueue += OnCheckQueue;
}
private static event EventHandler checkQueue = delegate { };
private static async void OnCheckQueue(object sender, EventArgs args) {
cts = new CancellationTokenSource();
PrintJob job = null;
while (!queue.IsEmpty && queue.TryDequeue(out job)) {
await Print(job);
if (cts.IsCancellationRequested) {
break;
}
}
idle = true;
}
public void Enqueue(PrintJob job) {
queue.Enqueue(job);
if (idle) {
lock (syncLock) {
if (idle) {
idle = false;
checkQueue(this, EventArgs.Empty);
}
}
}
}
public void Cancel() {
if (!cts.IsCancellationRequested)
cts.Cancel();
}
static Task Print(PrintJob job) {
//...print job
}
}
which takes advantage of async event handlers to process the queue in sequence as jobs are added.
The Cancel is provided so that the process can be short circuited as needed.
Like in Application_End event as suggested by another user
var agent = new DefaultPrintAgent();
agent.Cancel();
or manually by exposing an endpoint if so desired.

Resources