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

Update WriteHttpResponse.cs to call response.CompleteAsync() #5268

Closed
wants to merge 1 commit into from

Conversation

ciaranodonnell
Copy link
Contributor

@ciaranodonnell ciaranodonnell commented Apr 24, 2024

I think this is the fix to bug #5267

If we call the CompleteAsync() on the response it will flush the response to the client. This fixes the issue in our testing and the response is written immediately.


This change is Reviewable

@jdevillard
Copy link
Contributor

Hello Thanks for this, it seems to fix some part of the issue.
Have you do some test on Error handling in the Workflow?

If the workflow throw an exception after the HttpResponse, the code seems to try to WriteAsync with the HttpContext.Response which I think will throw another exception.

Need to check some tests.

@sfmskywalker
Copy link
Member

Good point. Perhaps that error handling code needs to check to see if a response is already being sent, and if so, ignore it.
In that light, I also wonder if there may exist a scenario where one might want to actually wait for the full workflow to complete before flushing the response? If yes, perhaps this behavior should be configurable through a checkbox on the activity. What do you think @ciaranodonnell @jdevillard ?

@jdevillard
Copy link
Contributor

Good point. Perhaps that error handling code needs to check to see if a response is already being sent, and if so, ignore it. In that light, I also wonder if there may exist a scenario where one might want to actually wait for the full workflow to complete before flushing the response? If yes, perhaps this behavior should be configurable through a checkbox on the activity. What do you think @ciaranodonnell @jdevillard ?

What will be the difference between placing the HttpResponse activity in the middle with a checkbox to wait until the end and placing the activity at the end of the Workflow?

And also if the Workflow is Suspended the Middleware release the client and a response is sent, so even with the checkbox, we could have some behavior not easily visible by the user.

Last though, if we really wait to respond to the caller to handle something wrong, the caller will be able to handle some internal exception about the infrastructure. For example, today, there is a delay between the last activity (httpResponse) and the end of the workflow because the middleware flush the call after all the persistence behavior. If there is any issue on the persistence, the call will have a 400/500 , the idea is to determine what is the concern of the caller about the internal Workflow mecanism or just the execution of the workflow.

@sfmskywalker
Copy link
Member

What will be the difference between placing the HttpResponse activity in the middle with a checkbox to wait until the end and placing the activity at the end of the Workflow?

That's a great point; after all, why would the author of the workflow put the HTTP Response activity before the remaining activities.

@ciaranodonnell what scenario do you have in mind that requires the HTTP Response activity to happen before the end of the workflow?

The concern with sending back the response while the workflow is still executing, is what happens in case of errors later on, like @jdevillard explains.

Perhaps the scenario is to continue the remainder of the workflow asynchronously from a background process?

@jdevillard
Copy link
Contributor

@ciaranodonnell what scenario do you have in mind that requires the HTTP Response activity to happen before the end of the workflow?

@sfmskywalker on this point, I've the same use case and it is the following. I've got a Stream Log Processing of a SaaS application which flush his data calling an Workflow Endpoint of Elsa. But this call need to execute in less than 5 sec, otherwise, the client close the connexion and throw an error.

So I've to acknowledge quickly that I've considered the request and be able to handle this (maybe later) but the Caller has done his work.

Perhaps the scenario is to continue the remainder of the workflow asynchronously from a background process?

yes I think it could be good, can we consider this implementation as a second step? and for now just :

  • call CompleteAsync()
  • add the test to avoid issue if CompleteAsync() has already been called

This will solve other Perf issue in my sense.

@sfmskywalker
Copy link
Member

sfmskywalker commented Apr 26, 2024

@jdevillard Yes, we could just add the call to CompleteAsync, but then there's the potential for an error happening in subsequent parts of the HTTP request context, which the client will now not receive, as per your earlier observation. This may or may not be acceptable, depending on a case by case and depending on who you ask. For this reason, I propose to bind it to a checkbox, so that the user can make a conscious choice whether or not to accept this risk. In case of performance requirements, such as the one you described, this could be an acceptable risk, so you tick the checkbox.

@ciaranodonnell
Copy link
Contributor Author

What will be the difference between placing the HttpResponse activity in the middle with a checkbox to wait until the end and placing the activity at the end of the Workflow?

That's a great point; after all, why would the author of the workflow put the HTTP Response activity before the remaining activities.

@ciaranodonnell what scenario do you have in mind that requires the HTTP Response activity to happen before the end of the workflow?

The concern with sending back the response while the workflow is still executing, is what happens in case of errors later on, like @jdevillard explains.

Perhaps the scenario is to continue the remainder of the workflow asynchronously from a background process?

We call a Workflow with Http and have the respond activity be the very next activity that confirms the workflow has started. After that all out progress in the workflow is published as events.
As a user I expect that when the "Respond to the call" activity completes and moves on that the response is sent. If I want the response to be contingent on remaining activities, I would put it at the end.

@ciaranodonnell
Copy link
Contributor Author

@jdevillard Yes, we could just add the call to CompleteAsync, but then there's the potential for an error happening in subsequent parts of the HTTP request context, which the client will now not receive, as per your earlier observation. This may or may not be acceptable, depending on a case by case and depending on who you ask. For this reason, I propose to bind it to a checkbox, so that the user can make a conscious choice whether or not to accept this risk. In case of performance requirements, such as the one you described, this could be an acceptable risk, so you tick the checkbox.

I don't think the checkbox is unreasonable as a Back-Compat feature considering this is already out in the wild. I can add the check box today and add a test to that behavior. I'll try to update the PR today.

@sfmskywalker
Copy link
Member

@ciaranodonnell On second thought, I think the expectation that you described makes sense. So maybe, instead of doing the checkbox thing, it should be a system-wide flag that controls the behavior. Let's consider the current behavior as faulty. To opt-in into the corrected behavior (the one you're proposing via this PR), the developer can set this flag. This way, we can change the flag in a later version, where one would have to opt-out if they want to stick to the current behavior.

@jdevillard What do you think?

@jdevillard
Copy link
Contributor

Ok for me !

@jdevillard
Copy link
Contributor

Hello @ciaranodonnell ,

Hope your are doing well. Do you agree with the flag concept ?

Will you get some time to update your PR ?

@jdevillard
Copy link
Contributor

@ciaranodonnell Thanks for hitting this issue and your contribution.
Your code was merged in #5446

@jdevillard jdevillard closed this May 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants