YMQ -> python exception handling #159
Replies: 6 comments 15 replies
-
|
From my discussion with @gxuu regarding how to pass back asynchronous unrecoverable errors from the core. The idea is to have a global callback. This is pseudocode. I will post the definition of // in c++ core
static void (*function_hook)(Exception ex) = nullptr;
extern void global_error_hook(Exception ex) {
if (function_hook)
function_hook();
else {
// If no hook is set, we can log the error or handle it in a default way
std::cerr << "No error hook set. Exception: " << ex.what() << std::endl;
std::abort(); // Terminate the program
}
}
// python interface
#include "core.h" // import c++ core
void global_error_hook(Exception ex) {
acquire_gil();
python_fatal_exception("An error occurred in the C++ core: " + ex.what());
release_gil();
}
void module_init() {
// Set the global error hook to the Python interface
function_hook = global_error_hook;
}
// c++ interface
void global_error_hook(Exception ex) {
std::cerr << "Fatal error in C++ core: " << ex.what() << std::endl;
std::abort(); // This will terminate the program
}
void main() {
function_hook = global_error_hook; // Set the C++ core error hook
} |
Beta Was this translation helpful? Give feedback.
-
Errors and Exceptions in YMQHere I will try to summarize my thoughts and ideas that have arisen from discussions with @gxuu regarding error and exception handling in YMQ. Two Kinds of ErrorsI feel that it's important to distinguish between two kinds of errors: Errors arising from the system (e.g. errno), and those coming from our own invariants which I will call "logical" errors. The first class of errors should be quite clear, you can imagine for example that the user (Python code) is sending a message, but The logical class of errors are those that we create ourselves, this could include for example things like trying to create two sockets with the same identity, trying to create a socket with an empty identity (debatable on whether or not we should allow this), trying to bind a Thus, we will need a way to represent both kinds of errors in our Asynchronous ErrorsMany operations in the core are the result of a direct request from the user, for example Python code trying to send a message directly causes However errors can arise in other contexts. The core does some work behind the scenes that are not at the direct request of a user, for example what should the core do if a socket's connection suddenly drops? Well, we know this, the core should try to reconnect it 'transparently', i.e. without any intervention from the user. In this case we would 'swallow' the error, we handle it internally and the user need not do anything. However, not all errors can be handled within the core, for example We need to communicate this back to the user somehow, but because this operation was not directly requested by the user, we have no callback. I thus propose a "global error hook", a global function that can be called with the exception and is defined by the user of the library. In the case of Python, we can acquire the GIL, report the error, then gracefully shut down the interpreter. For pseudocode, see the previous comment. The Exception TypeI propose the following exception type. Please note that this is subject to change, names, etc. are NOT final. enum Syscall {
Read,
Write,
Accept,
Bind,
// etc.
};
enum Logical: int {
DuplicateIdentity = -1,
// etc.
};
struct Exception {
int errno; // > 0 means errno, < 0 means `Logical`
Syscall syscall;
};
void demo() {
auto exc1 = Exception { .errno = (int)Logical::DuplicateIdentity };
auto exc2 = Exception { .errno = EADDRINUSE, .syscall = Syscall::Bind };
}Without Type PunningThis makes use of type punning to store the errno and logical error cases within the same variable. The // alternative
struct Exception {
enum { System, Logical } tag;
union {
Logical logical;
struct { int errno; Syscall syscall };
};
};This can be used to achieve the same thing, but is more verbose. I am equally ok with both of these options, please let me know if you have a preference: @sharpener6, @gxuu. Representation in PythonI will have to create an exception class in Python to match what we do in C++. The translation here should be quite straightforward, but I'll show it to you before I implement it. |
Beta Was this translation helpful? Give feedback.
-
|
Reference implementation of error and its utility can be found here. All |
Beta Was this translation helpful? Give feedback.
-
|
We just had a call with @gxuu, here is what we came up with for error handling. A base class YMQError : public std::exception {
public:
enum class ErrorType {
ConnectionReset,
WriteError,
...
};
YMQError(ErrorType errorType, Args&&... args);
const char* what() const noexcept override;
ErrorType getErrorType() const;
private:
ErrorType errorType;
std::string message;
};The YMQError(ErrorType.WriteError, "Unable to write to socket, errno=%d", errno)Most of the time, YMQ will raise this error object back to the user through class IOSocket {
...
void recvMessage(std::function<std::expected<Message, YMQError>> onRecvMessage) noexcept;
...
}In addition, there are cases where YMQ cannot recover. There are unexpected errors that the library cannot recover from and should terminate. In these cases, the library will call a Message* msg = new Message();
if (msg == nullptr) {
unrecoverableError({ErrorType.MemoryError, "Unable to allocate memory"});
}We will allow the user to set a specific handler for these errors. The reason is that the user might want to do some cleanup operations: void scalerUnrecoverableErrorHandler(YMQError error) {
// Do some Python related cleanup
...
Py_Finalize();
}
setUnrecoverableErrorHandler(scalerUnrecoverableErrorHandler);The default error handler would just print the error message and exit the process. Please note that this does not address logging yet. |
Beta Was this translation helpful? Give feedback.
-
|
Reference implementation to the aforementioned call can be found at scaler/io/ymq/error.h. Reference usage to the implementation can be found at scaler/io/ymq/utils.h.
Note that,
To address logging, we might want to change |
Beta Was this translation helpful? Give feedback.
-
|
Implementation to the Logging can be found in |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
@gxuu, @magniloquency, please put your ideas here and pros and cons here
Beta Was this translation helpful? Give feedback.
All reactions