-
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
Should errors be reported programatically instead of/as well as being logged #40
Comments
I have been thinking about this for a long while - pretty much when starting out conceiving this library. I did not come up with a definitive design yet as for the various problems you mentioned. I agree that the I don't mind using exceptions as much as some other C++ developers do. But I do see problems with using exceptions to handle problems within this library. You outlined it pretty well. |
I like the way beast and asio handles them, with the codes passed to the callback functions or as out params for sync versions, but it still leaves the issue of how to report on the server side. I think we also need to question if we want to report (setup/routing) errors on the server side. iirc neither flask nor django offer anything but logging for errors that occure before the handler is invoked, I assume because theres nothing that could be done about it from the users perspective. It might be worth considering adding an |
Just some more info for this discussion, after some further coroutine research. The asio docs have this to say about coroutine versions of async functions (emphasis mine):
void handler(boost::system::error_code ec, result_type result);
(docs) Based on my understanding of coroutines, this will mean the exception is propagated upward until it hits a non-coroutine function at which point it is effectively "unwrapped" (like how future/promise pairs work with However, if we went the error code route it would also prevent switching to coroutines as currently supported by asio without either some exception catching layer or some major breaking changes. Also compiler support is still patchy (iirc latest msvc only has the ts, and clang hasn't implemented it fully. gcc has though). Going with this would also require a reshuffle of both Finally, yet another option could be to catch the exception thrown by asio and wrap it in our own type like |
Personally, I'd want to wait with migrating "everyting" to co-routines anyway. I looked into this when starting to write this library and compiler support seemed less-than-ideal. I am still thinking about this pretty much every day. I still haven't made up my mind but I do think that I'd tend towards creating a custom error reporting interface (something similar to What is your current, overall "feeling" about this situation? |
I agree with the waiting on coroutines. Compiler support is soso and it would be a pretty major change. I like the custom error reporting interface in theory, but I'm not clear on what form that would take. My general feeling though is that we should be using callbacks or overwise chainable things for error reporting, and try and avoid stuff that requires blocking like |
Me neither - otherwise this would have been done long before you joined in :p
I fully agree.
C++ is not the language where a library author necessarily has to prevent the user from shooting himself in the foot.
Anyway, I have been thinking about this some more. I think that we should design the error interface in a way that it's also extendible. For example, I have two applications (consuming |
I've been thinking about this some more, and I think it would be helpful to categorise the types of errors we are going to have to have to communicate, based on how they can/could be handled by user code. 1. Stuff which the user cannot actually do anything about, apart from maybe log it themselvesimo this is stuff like errors with the server side before it hits the handler. Even those might fall into (3) though. This should just be logged in a user-customisable fashion and dealt with internally by malloy. 2. General issues which may or may not be classed as errors by the usere.g. failing to close a websocket because the other end did it already, or failing to resolve an endpoint. These are probably going to be most of the errors and should be the focus when thinking about how to report imo. My current thoughts on this is we should use error codes and callbacks. This should cover most bases, with the exceptions (scuse the pun) being ctors and dtors. Alternatively it might be possible to roll our own 3. Critical/fatal errors which the user may be able to deal with/work aroundThese are errors which stop
but I would prefer to have a system that at least warned the user that the gun was live in the first place :p (to strech the metaphore a little). Reporting of these should be done via exceptions imo. They are the built-in mechanism for reporting hard errors and are difficult/impossible to ignore unless one wants to. One of the issues with this is using it with async code, however I think the current use cases for this type of error are entirely synchronous code (startup stuff and preconditon checking). Examples of stuff which should throw (and currently return bool): 4. Stuff that may bubble up through malloy from user codeSince we use callbacks for a lot of things, it seems likely that malloy will have to handle some exceptions that escape these. We could just say "no" to them escaping and do an All of this is of course just my opinion :p. Thoughts? |
Well, I couldn't agree more. This is a very good write-up of my thoughts of the last few weeks/months. Thank you for going through the trouble of writing this out :p One thing I would like to specifically mention tho: I am strongly against calling |
So can I start work on converting some of the current |
This is more of a design question that I just wanted to put out there. Currently the library generally deals with errors by logging them with a user-provided logger and moving on. The use of user-provided loggers allows suppressing or custom reporting of the errors in a customisable way. However, it does not let the user of the library take action if a problem occures, such as being unable to connect (in which case the user may want to try again, for example).
One way to report errors would be through C++'s built-in method of exceptions. I like exceptions personally but I think this is not a great place for them because A) They do not mesh well with async stuff yet (although coroutines will hopefully improve that) and B) Some things are not neccarsarily exceptional for the user code, a server might frequently timeout for example.
Personally I very much like the
spdlog
intergration and I don't think that should be removed. But I also think there needs to be some way the user can handle errors. Thefuture/promise
route works well imo, but it is a single-use channel, so for stuff likeserver::router
thats no good. Another option would be a C# likeevent
that would allow registering multiple callbacks be fired on call. Then we could attach the logging code to said event, thus allowing the replacement of code which currently logs to instead fire the event, and have the user able to add their own handlers independently.As I said, I'm hoping for this to be somewhere we can discuss this, if there is already a policy in place I'm not aware of I apologise :p
Stuff that could benifit from this:
malloy/lib/malloy/server/http/connection/connection_tls.hpp
Line 82 in 9eecc9c
malloy/lib/malloy/websocket/stream.hpp
Line 75 in 9eecc9c
It is worth noting that the client-side currently has quite a bit of error feedback currently.
http_request
gives anfuture<error_code>
and the callback formake_websocket_connection
may get invoked on an error (but some are just logged), however the use ofstd::future
for the reporting mechanism is somewhat problematic because it can't be waited on asynchronously afaik. I thinkboost::asio::awaitable
could solve this and I will be investigating at some pointThe text was updated successfully, but these errors were encountered: