Why does on_command_error fire when I have already ignored a message that is a bad command? - command

I have the following 2 listeners in the sole cog for my bot:
#Cog.listener()
async def on_command_error(self, ctx, error) :
if isinstance(error, CommandNotFound):
await ctx.send_help()
#Cog.listener()
async def on_message(self, message):
if message.author.bot:
return
if message.content.startswith(">--"):
return
The command prefix is >-, and I was under the impression that the return for messages starting with >-- would mean that the message goes no further than on_message, yet when I give the command >--halp, on_command_error fires with the error:
CommandNotFound('Command "-halp" is not found')
Is my understanding of how to ignore messages fault, or does on_command_error even fire for "dead" messages, or what am I doing wrong?

Registering a listener inside of a cog does not replace the default one used by the bot (if a default exists).
In your case, every time a message is sent to a channel the bot can see, both the custom on_message event in the cog as well as the default on_message event will trigger.
This is why the CommandNotFound error is raised, since the default on_message event still tries to process the message and check if a command was called.
If you override the default on_message event in your main file (where your bot client is defined), then both custom on_message events will still trigger (the main and the cog).
This can be verified with the below. When the bot sees a message, both bot.py and cog.py will be printed, indicating both on_message events are triggered.
bot.py
from discord.ext import commands
client = commands.Bot(command_prefix='>-')
client.load_extension('cog')
#client.event
async def on_message(message):
print('bot.py')
await client.process_commands(message)
client.run('TOKEN')
cog.py
from discord.ext import commands
class TestCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_message(self, message):
print('cog.py')
def setup(bot):
bot.add_cog(TestCog(bot))
If you want the bot to completely ignore certain messages, then you need to do so in a custom on_message event in the file where the bot client is defined.

Related

Timing of `postMessage` inside service worker `fetch` event handler

I have a simple service worker which, on fetch, posts a message to the client:
// main.js
navigator.serviceWorker.register("./service-worker.js");
console.log("client: addEventListener message");
navigator.serviceWorker.addEventListener("message", event => {
console.log("client: message received", event.data);
});
<script src="main.js"></script>
// service-worker.js
self.addEventListener("fetch", event => {
console.log("service worker: fetch event");
event.waitUntil(
(async () => {
const clientId =
event.resultingClientId !== ""
? event.resultingClientId
: event.clientId;
const client = await self.clients.get(clientId);
console.log("service worker: postMessage");
client.postMessage("test");
})()
);
});
When I look at the console logs, it's clear that the message event listener is registered after the message is posted by the service worker. Nonetheless, the event listener still receives the message.
I suspect this is because messages are scheduled asynchronously:
postMessage() schedules the MessageEvent to be dispatched only after all pending execution contexts have finished. For example, if postMessage() is invoked in an event handler, that event handler will run to completion, as will any remaining handlers for that same event, before the MessageEvent is dispatched.
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Notes
However, I'm not sure what this means in this specific example. For example, when the fetch event handler has ran to completion, is the client JavaScript guaranteed to have ran, and therefore the message event listener will be registered?
I have a larger app that is doing something similar to the above, but the client JavaScript is ran slightly later in the page load, so I would like to know when exactly the event listener must be registered in order to avoid race conditions and guarantee the message posted by the service worker will be received.
By default, all messages sent from a page's controlling service worker to the page (using Client.postMessage()) are queued while the page is loading, and get dispatched once the page's HTML document has been loaded and parsed (i.e. after the DOMContentLoaded event fires). It's possible to start dispatching these messages earlier by calling ServiceWorkerContainer.startMessages(), for example if you've invoked a message handler using EventTarget.addEventListener() before the page has finished loading, but want to start processing the messages right away.
https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/startMessages

How to handle commands sent from saga in axon framework

Using a saga, given an event EventA, saga starts, it sends a command (or many).
How can we make sure that the command is sent successfully then actual logic in other micro-service did not throw, etc.
Let's have an example of email saga:
When a user register, we create a User Aggregate which publishes UserRegisteredEvent, a saga will be created and this saga is responsible to make sure that registration email is sent to user (email may contain a verification key, welcome message, etc).
Should we use :
commandGateway.sendAndWait with a try/catch -> does it scale?
commandGateway.send and use a deadline and use some kind of "fail event" like SendEmailFailedEvent -> requires to associate a "token" for commands so can associate the "associationProperty" with the correct saga
that sent SendRegistrationEmailCommand
commandGateway.send(...).handle(...) -> in handle can we reference eventGateway/commandGateway that were in MyEmailSaga?
If error we send an event? Or can we modify/call a method from the saga instance we had. If no error then other service have sent an event like "RegistrationEmailSentEvent" so saga will end.
use deadline because we just use "send" and do not handle the eventual error of the command which may have failed to be sent (other service is down, etc)
something else?
Or a combination of all?
How to handle errors below? (use deadline or .handle(...) or other)
Errors could be:
command has no handlers (no service up, etc)
command was handled but exception is raised in other service and no event is sent (no try/catch in other service)
command was handled, exception raised and caught, other service publish an event to notify it failed to send email (saga will receive event and do appropriate action depending on event type and data provided -> maybe email is wrong or does not exist so no need to retry)
other errors I missed?
#Saga
public class MyEmailSaga {
#Autowired
transient CommandGateway commandGateway;
#Autowired
transient EventGateway eventGateway;
#Autowired
transient SomeService someService;
String id;
SomeData state;
/** count retry times we send email so can apply logic on it */
int sendRetryCount;
#StartSaga
#SagaEventHandler(associationProperty = "id")
public void on(UserRegisteredEvent event) {
id = event.getApplicationId();
//state = event........
// what are the possibilities here?
// Can we use sendAndWait but it does not scale very well, right?
commandGateway.send(new SendRegistrationEmailCommand(...));
// Is deadline good since we do not handle the "send" of the command
}
// Use a #DeadlineHandler to retry ?
#DeadlineHandler(deadlineName = "retry_send_registration_email")
fun on() {
// resend command and re-schedule a deadline, etc
}
#EndSaga
#SagaEventHandler(associationProperty = "id")
public void on(RegistrationEmailSentEvent event) {
}
}
EDIT (after accepted answer):
Mainly two options (Sorry but kotlin code below):
First option
commandGateway.send(SendRegistrationEmailCommand(...))
.handle({ t, result ->
if (t != null) {
// send event (could be caught be the same saga eventually) or send command or both
}else{
// send event (could be caught be the same saga eventually) or send command or both
}
})
// If not use handle(...) then you can use thenApply as well
.thenApply { eventGateway.publish(SomeSuccessfulEvent(...)) }
.thenApply { commandGateway.send(SomeSuccessfulSendOnSuccessCommand) }
2nd option:
Use a deadline to make sure that saga do something if SendRegistrationEmailCommand failed and you did not receive any events on the failure (when you do not handle the command sent).
Can of course use deadline for other purposes.
When the SendRegistrationEmailCommand was received successfully, the receiver will publish an event so the saga will be notified and act on it.
Could be an RegistrationEmailSentEvent or RegistrationEmailSendFailedEvent.
Summary:
It seems that it is best to use handle() only if the command failed to be sent or receiver has thrown an unexpected exception, if so then publish an event for the saga to act on it.
In case of success, the receiver should publish the event, saga will listen for it (and eventually register a deadline just in case); Receiver may also send event to notify of error and do not throw, saga will also listen to this event.
ideally, you would use the asynchronous options to deal with errors. This would either be commandGateway.send(command) or commandGateway.send(command).thenApply(). If the failure are businesslogic related, then it may make sense to emit events on these failures. A plain gateway.send(command) then makes sense; the Saga can react on the events returned as a result. Otherwise, you will have to deal with the result of the command.
Whether you need to use sendAndWait or just send().then... depends on the activity you need to do when it fails. Unfortunately, when dealing with results asynchronously, you cannot safely modify the state of the Saga anymore. Axon may have persisted the state of the saga already, causing these changes to go lost. sendAndWait resolves that. Scalability is not often an issue, because different Sagas can be executed in parallel, depending on your processor configuration.
The Axon team is currently looking at possible APIs that would allow for safe asynchronous execution of logic in Sagas, while still keeping guarantees about thread safety and state persistence.

Outlook Addin Event handler clean up

I am having problems with the event handler in my office addin . Below is an example code i got from microsoft website to explain what i mean.
I have a manifest file that uses the on-send hook as well as a click-based event triggering.
My button calls appendMessageBodyOnClick and onsend i call appendMessageBodyOnSend. Both function primarily do the same thing. I never want to block sending emails regardless.
The problem is that the event object is not properly cleaned up i think.
Scenario 1
When i click my button ; which calls event.completed(), and then after i try to send the message, it says my app is blocking the message, but then when i try to send again it goes through.
Scenario 2
When i leave the subject empty and then send the message, as expected i am prompted that the subject is empty. If i cancel sending the message on this note and then click on my button, the message tries to send as though i clicked send.
I am supposing the is some sort or state clean up issue. What am i doing wrong here?
Function-File.js
function appendMessageBodyOnClick(event) {
// Append string to message body
event.completed();
}
// In the following example, the checkMessage function has
// been registered as an event handler for ItemSend.
function appendMessageBodyOnSend(event) {
// Append string to message body
event.completed({allowEvent = true});
}
Not sure if this will help, but I also have faced some seemingly inconsistent behavior while understanding how to signal that event is fully completed. Once I got my edge cases fixed, then it worked.
One suggestion: Appending string to message body should be an async function. Call the event.completed() from inside the callback function. (i.e: make sure when you are calling event.completed(), nothing else is pending -like another async result)
Something like the following:
Office.context.mailbox.item.body.setAsync("new body", function(asyncResult) {
// handle success and failure
event.completed()
});
Same would be for your scenario 2, make sure event.completed() is called at the very end.

Akka remoting: Remote subscribed event listener custom serialising a Watch message

I have the following remote actor set up.
actorSystem.actorSelection(remoteConfig.getString("/myEventListener")).resolveOne().map{ar =>
actorSystem.eventStream.subscribe(ar, classOf[MyEvent])
}
I also have my own custom serialization. The issue is that this gets sent a Watch message which has the following signature:
private[akka] final case class Watch(watchee: InternalActorRef, watcher: InternalActorRef) extends SystemMessage
Which is not so straight forward to serialize. Any suggestions on how to proceed on this one? Sending a remote message with references to InternalActorRef seems a bit of an odd one.
And to note I use other remote actors directly (not as event listeners), these dont get sent the Watch message:
val emailService = actorSystem.actorSelection(remoteConfig.getString("/emailCommandHandler"))

Update actor state only after all events are persisted

In the receive method of a persistent actor, I receive a bunch a events I want to persist, and only after all events are persisted, update again my state. How can I do that?
def receive: Receive = {
...
case NewEvents(events) =>
persist(events) { singleEvent =>
// Update state using this single event
}
// After every events are persisted, do one more thing
}
Note that the persist() call is not blocking so I cannot put my code just after that.
Update: Why I need this
These new events come from an external web-service. My persistent actor needs to store in its state the last event id, which will be used for the subsequent ws call when it receives a command. The thing is that these commands may come concurrently, so I need some kind of locking system:
Received ws call command: stash next commands until this one finishes (that is, to sum up, a boolean)
Received responses from ws: store them, update the state and save the last id, execute another, single ws call for all commands that are in the stash (I'm keeping the command senders to be able to respond to them all once done) otherwise don't stash commands anymore.
I haven't tried defer yet, my initial solution was to send myself a PersistEventsDone message. It works because the persist method will stash all incoming messages until all the events handlers are executed. If another command came in the process, it doesn't really matter if it's before or after PersistEventsDone:
def receive: Receive = {
...
case PersistEventsDone =>
...
case NewEvents(events) =>
persist(events) { singleEvent =>
// Update state using this single event
}
self ! PersistEventsDone
}
defer is a bit weird in my case because it requires an event I don't need. But it still looks more natural than my solution.