Drop / skip messages - C++ Actor Framework (CAF) - c++-actor-framework

Using the C++ Actor Framework (CAF), I want to be able to skip / drop messages. E.g. incoming messages are being received at 100Hz. I only want the receiving actor to process messages at 1Hz (skipping 99 messages per second).
Does CAF provide any native functionality to do this?
Thanks.

There is support for both skipping and dropping. Skipping leaves messages in the mailbox, allowing actors to process it some later point after changing their behavior. Dropping is generally viewed as an error (unexpected messages).
The mechanism to do is in CAF is via default handlers. CAF dispatches any message that was not processed by the current behavior to a "fallback", which then decides what to do with the unmatched input.
You can override this handler however you want, but CAF also offers standard implementations to choose from:
skip: leaves the message in the mailbox. This message gets automatically re-matched later.
drop: considered an error. Terminates the receiver with an unexpected_message error, also sending an error message to the sender.
print_and_drop: like drop, but also prints an error to stderr (this is the default).
CAF also comes with examples showcasing how to use these handlers, e.g., https://github.com/actor-framework/actor-framework/blob/master/examples/dynamic_behavior/skip_messages.cpp. If you are looking for a "silent" drop that discards the message without an error:
caf::skippable_result silent_drop(scheduled_actor*, message&) {
return caf::message(); // "void" result
}
All that being said, if all you are looking for is simply checking that some amount of time has passed before processing the next message: why not just leave the message handler early?
caf::behavior my_actor(caf::stateful_actor<my_state>* self) {
return {
[](const my_input& x) {
if (!self->state.active())
return;
// ...
}.
};
}
Here, the idea is that active returns true only if some amount of time has passed since last processing a message.

Related

Axon Partialy replay, how do i get a TrackingToken for the startPosition for the replay?

I want my Axon replay events, not all but partially.
A full replay is up and running but when i want a partially replay i need a TrackingToken startPosition for the method resetTokens(), my problem is how to get this token for the partial replay?
I tried with GapAwareTracingToken but this does not work.
public void resetTokensWithRestartIndexFor(String trackingEventProcessorName, Long restartIndex) {
eventProcessingConfiguration
.eventProcessorByProcessingGroup(trackingEventProcessorName, TrackingEventProcessor.class)
.filter(trackingEventProcessor -> !trackingEventProcessor.isReplaying())
.ifPresent(trackingEventProcessor -> {
// shutdown this streaming processor
trackingEventProcessor.shutDown();
// reset the tokens to prepare the processor with start index for replay
trackingEventProcessor.resetTokens(GapAwareTrackingToken.newInstance(restartIndex - 1, Collections.emptySortedSet()));
// start the processor to initiate the replay
trackingEventProcessor.start();
});
}
When i use the GapAwareTrackingToken then i get the exception:
[] - Resolved [java.lang.IllegalArgumentException: Incompatible token type provided.]
I see that there is also a GlobalSequenceTrackingToken i can use, but i don't see any documentatieon about when these can/should be used.
The main "challenge" when doing a partial reset, is that you need to be able to tell where to reset to. In Axon, the position in a stream is defined with a TrackingToken.
The source that you read from will provide you with such a token with each event that it provides. However, when you're doing a reset, you probably didn't store the relevant token while you were consuming those events.
You can also create tokens using any StreamableMessageSource. Generally, this is your Event Store, but if you read from other sources, it could be something else, too.
The StreamableMessageSource provides 4 methods to create a token:
createHeadToken - the position at the most recent edge of the stream, where only new events will be read
createTailToken - the position at the very beginning of the stream, allowing you to replay all events.
createTokenAt(Instant) - the most recent position in the stream that will return all events created on or after the given Instant. Note that some events may still have a timestamp earlier than this timestamp, as event creation and event storage isn't guaranteed to be the same.
createTokenSince(Duration) - similar to createTokenAt, but accepting an amount of time to go back.
So in your case, createTokenAt should do the trick.

How to wait for all completed AsyncOperations on app close

I'm sending messages using an asynchronous write operation, but when the app is closed I need to write 2 messages to a device, but only 1 message gets successfully written.
Each write operation is chained to a message queue, so the messages write operations are sent sequentially after each completed write operation while the message queue is full. So basically the following code might get to the first completed callback, but it doesn't reach the 2nd before the app closes. I tried adding a Windows Sleep call in between and after Async Operations, but this didn't work. I also tested waiting for the completion callback using a while loop to see if the 2nd opertation ever completes, which it never does.
ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
GattWriteOption option = GattWriteOption_WriteWithoutResponse;
hr = customCharacteristic->WriteValueWithOptionAsync(buffer.Get(), option, &writeOp);
hr = writeOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>
(this, &DataGloveBluetooth::OnCharacteristicWriteComplete).Get());
This is only an issue on app close as it seems 2nd operation never gets to the callback. Also, the messages are too large to put together, so I need to be able to send more than 1 message.
Is there a proper way I can wait? This is some pseudo-code to help explain the ordering:
WriteMessage(LED_RESET); // adds to message queue, then calls aync op,
WriteMessage(CLOSE); // adds to message queue, async op is called once first message is sent, complete callback is never reached
Sleep(5000) // whatever sleep amount never helps the 2nd message finish

How to get specified message from Azure Service Bus Topic and then delete it from Topic?

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.

Does C++ Actor Framework guarantee message order?

Can C++ Actor Framework be used in such a way that it guarantees message ordering between two actors? I couldn't find anything about this in the manual.
If you have only two actors communicating directly, CAF guarantees that messages arrive in the order they have been sent. Only multi-hop scenarios can cause non-determinism and message reordering.
auto a = spawn(A);
self->send(a, "foo");
self->send(a, 42); // arrives always after "foo"
At the receiving end, it is possible to change the message processing order by changing the actor behavior with become:
[=](int) {
self->become(
keep_behavior,
[=](const std::string&) {
self->unbecome();
}
);
}
In the above example, this will process the int before the string message, even though they have arrived in opposite order at the actor's mailbox.

interrupted system call error when writing to a pipe

In my user space Linux application, I have a thread which communicated to the main process through a pipe. Below is the code
static void _notify_main(int cond)
{
int r;
int tmp = cond;
r = write( _nfy_fd, &tmp, sizeof(tmp) );
ERROR( "write failed: %d. %s\n", r, strerror(r) );
}
Pretty straight forward. It's been working fine for quite a while now. But recently, the write call will fail with "interrupted system call" error after the programme went under some stress test.
Strangely, the stuff actually went through the pipe no problem. Of course I'd still like to go to the bottom of the error message and get rid of it.
Thanks,
The write(2) man page mentions:
Conforming to
SVr4, 4.3BSD, POSIX.1-2001.
Under SVr4 a write may be interrupted and return EINTR at any point, not just before any data is written.
I guess you were just lucky that it didn't occur so far.
If you google just for the "interrupted system call", you will find this thread which tells you to use siginterrupt() to auto-restart the write call.
From http://www.gnu.org/
A signal can arrive and be handled while an I/O primitive such as open
or read is waiting for an I/O device. If the signal handler returns,
the system faces the question: what should happen next?
POSIX specifies one approach: make the primitive fail right away. The
error code for this kind of failure is EINTR. This is flexible, but
usually inconvenient. Typically, POSIX applications that use signal
handlers must check for EINTR after each library function that can
return it, in order to try the call again. Often programmers forget to
check, which is a common source of error.
So you can handle the EINTR error, there is another choice by the way, You can use sigaction to establish a signal handler specifying how that handler should behave. Using the SA_RESTART flag, return from that handler will resume a primitive; otherwise, return from that handler will cause EINTR.
see interrupted primitives

Resources