-
Notifications
You must be signed in to change notification settings - Fork 8
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
Protect against errors raised when adding a request to the engine #230
Conversation
RequestOutput( | ||
req_id, | ||
sequences=[], | ||
error=err_msg, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By returning a non-None error here, the exception is now raised at https://github.com/octoml/mlc-llm/blob/batch-serving/serve/mlc_serve/engine/async_connector.py#L88-L89 like
File "/home/masahi/projects/dev/mlc-llm/serve/mlc_serve/api/handler.py", line 159, in request_completion
return await collect_result_stream(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/masahi/projects/dev/mlc-llm/serve/mlc_serve/api/handler.py", line 233, in collect_result_stream
async for res in result_generator:
File "/home/masahi/projects/dev/mlc-llm/serve/mlc_serve/engine/async_connector.py", line 89, in generate
raise TextGenerationError(output.error)
mlc_serve.engine.error.TextGenerationError: Conversation roles must alternate user/assistant/user/assistant/...
Using the standalone MLC server, a client still gets openai.InternalServerError: Internal Server Error
as a response but the server doesn't die.
Would that be ok? I assume ollm has a proper response handling logic in such case @jroesch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes as long as we get an exception back we should catch and convert it properly!
d68566b
to
70e5918
Compare
) | ||
new_request_states.append(state) | ||
except Exception as e: | ||
LOG.warn("Failed to add a request", request_id=req.request_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will it be better to just throw the error here, and catch it at https://github.com/octoml/ollm/blob/d29be36231e666f761a2fb08dbf0e4ce758618f4/mlc-serve/mlc_serve/engine/async_connector.py#L153? I think initially we just assumed engine.add
cannot fail. Now it might be a good time to revisit this assumption. One caveat of the approach of deferring error reporting to the engine.step
is that, streaming API can no longer returns error status code once streaming begins (because of how server-sent event works)
Just sharing some thoughts. No need to block this PR if it's related to production issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that for its simplicity, and it also removes the need for an additional lock. I reworked this PR according to your suggestion, but I'm not sure what to do after catching the error in async_connector.py
. The following seems to work, but is this the right way?
try:
await asyncio.to_thread(self.engine.add, [request])
except TextGenerationError as e:
raise asyncio.CancelledError(e)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think any change is needed in async_connector
, but I am not fully sure. The TextGenerationError will just propagate to the http handler and the regular error handling can happen there. Because it's the engine.add
that fails, we don't need to call engine.cancel
either (as in https://github.com/octoml/ollm/blob/de6378ee6a1391276530e94b7b4374f01792c8ae/mlc-serve/mlc_serve/engine/async_connector.py#L99)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One benefit of throwing error in engine.add
is that the http handler will be able to respond with failure http status code for streaming requests. Throwing a CancelledError
will confuse the handler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed that not catching the error in async_connector.py
still keeps the server from dying.
Ready to merge? |
Previously, when an exception is raised at
get_new_request_state(...)
due to a malformed request, the server just dies.An example of such error
And a repro script
@yelite @elvin-n