Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot write intercepting middleware #130

Closed
brandonh-msft opened this issue Feb 15, 2018 · 14 comments
Closed

Cannot write intercepting middleware #130

brandonh-msft opened this issue Feb 15, 2018 · 14 comments
Assignees
Labels
bug Indicates an unexpected problem or an unintended behavior.

Comments

@brandonh-msft
Copy link
Contributor

Due to PR #118, it appears we can no longer write middleware that "intercepts" a message from the user (ie: doesn't call await next())

The easiest example is:

public class Interceptor : IMiddleware, IReceiveActivity
{
    public Task ReceiveActivity(IBotContext context, MiddlewareSet.NextDelegate next) => Task.CompletedTask;
}

because the above Middleware implementation doesn't call await next(), the hosting Bot's OnReceive should never be hit; however it will be.

cc @cleemullins @billba @ryanvolum

@ryanvolum
Copy link

@brandonh-msft and I have been writing the same middleware in both SDKs.

In the node SDK, this works to intercept messages:

export class TestMiddleware implements Middleware {
    public async receiveActivity(context: BotContext, next: () => Promise<void>): Promise<void> {
    }
}

As expected, not returning next effectively keeps the message from propagating through the rest of the middleware/bot logic, so a bot that uses this middleware is completely unresponsive.

@cleemullins
Copy link
Contributor

You can write Intercepting Middleware that manipulates the incoming Activity. You just can't currently PREVENT OnReceive from being called.

This is by design. The design may be incorrect, and if so we can change it. I'm open to how folks think this should work.

Current behavior is:

  1. Middleware is run. If Middleware calls next(), then then goto 1 until we're all done.
  2. Once All Receive Middlware is run OnReceive is called.

If I understand correctly you are asserting the following should be true:

  • If ALL Receive Middleware is run, and ALL of it calls next(), then (and only then) should OnReceive be called.

Is that accurate?

I'm not clear on what the behavior should be, as I can make a case either way.

@cleemullins
Copy link
Contributor

After a quick consult with @tomlm @Stevenic they both believe (as do you) that the following behavior should be what we have:

  • If ALL Receive Middleware is run, and ALL of it calls next(), then (and only then) should OnReceive be called.

@brandonh-msft
Copy link
Contributor Author

right; and that matches up with what the Node SDK is currently doing as @ryanvolum highlighted.

@RyanDawkins
Copy link

By intercept messages do you mean prevent them from being sent to the user? @brandonh-msft

@cleemullins
Copy link
Contributor

@brandonh-msft I'll probably get this taken care of late tonight or tomorrow.

@brandonh-msft
Copy link
Contributor Author

@RyanDawkins I mean you get a message from the user and your Middleware can do something that usurps the rest of the dialog flow of the bot (ie: everything that would've run as defined in OnReceive)

@ryanvolum
Copy link

@RyanDawkins This also means that the message doesn't flow through the following middleware of that pipe. This is to say that if you don't return next in receiveActivity, no other receiveActivity middleware will be called, BUT postActivity middleware will be called.

@RyanDawkins
Copy link

One way to prevent postActivity from returning back is to do IList.clear() on the activities parameter. That is how we are stopping messages from going to the user so we can make a list of messages delay as if the user is typing.

@ryanvolum
Copy link

ryanvolum commented Feb 16, 2018

That seems fine, though more generally not returning next should stop propagation through that pipe or the onReceive function

@Stevenic
Copy link
Contributor

@RyanDawkins we actually have a 'delay' activity that will let you insert a delay between activities.

@ryanvolum definitely agree that next() should stop propagation. One work around for now would be to look at the responses queue and just no-op your bots OnReceive() handler if there are already responses queued up.

@Stevenic Stevenic added the bug Indicates an unexpected problem or an unintended behavior. label Feb 16, 2018
@nrobert
Copy link
Contributor

nrobert commented Feb 19, 2018

@Stevenic , about the workaround you mentioned in the previous message: isn't there a problem with the QnAMaker middleware by doing this? As this middleware is setting responses if there is a match in the QnA

@Stevenic
Copy link
Contributor

@nrobert I haven't looked at the QnA Maker middleware implementation but i'm assuming it's currently designed to run on the leading edge of routing which is problematic in general. QnA Maker can be a bit aggressive about answering queries so more often than not you'd want to run it as a fallback if nothing else answers. With our latest middleware design you can do that but it looks like C# is currently missing a key addition that I made to the JS SDK to enable this.

You can code QnA Maker to run on the trailing edge of routing which means it will run after everything else has run but you need a way of knowing if the bot has already replied or not. You could look at the responses queue but that's not super reliable as it can get flushed (and it's going away soon) so on the JS side I added a read-only context.responded property you can check to see if any responses have been sent during the turn (it would be a great PR to add that to the C# side.) Using this flag QnA Maker could conditionally decide to run only when nothing else has sent a message.

@cleemullins
Copy link
Contributor

This is fixed by PR #146.

Tests around intercepting middleware have also been added into the test suite.
Test showing OnReceive slated to run.
Test showing OnReceive running when the Middlware pipeline is empty.
Test #1 showing an Intercepting Middleware.
Test #2 showing an Intercepting Middlware.

ceciliaavila added a commit that referenced this issue Jun 25, 2019
…iddleware

[StyleCop] Fix warnings in SlackEventMiddleware.cs and SlackMessageTypeMiddleware.cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or an unintended behavior.
Projects
None yet
Development

No branches or pull requests

6 participants