|
1 |
| -// TODO: Should I be using serde_derive instead of serde? |
| 1 | +//! Error handling is an important part of the `mem-isolate` crate. If something |
| 2 | +//! went wrong, we want to give the caller as much context as possible about how |
| 3 | +//! that error effected their `callable`, so they are well-equipped to know what |
| 4 | +//! to do about it. |
| 5 | +//! |
| 6 | +//! The primary error type is [`MemIsolateError`], which is returned by |
| 7 | +//! [`crate::execute_in_isolated_process`]. |
| 8 | +//! |
| 9 | +//! Philosophically, error handling in `mem-isolate` is organized into three |
| 10 | +//! levels of error wrapping: |
| 11 | +//! |
| 12 | +//! 1. The first level describes the effect of the error on the `callable` (e.g. |
| 13 | +//! did your callable function execute or not) |
| 14 | +//! 2. The second level describes what `mem-isolate` operation caused the error |
| 15 | +//! (e.g. did serialization fail) |
| 16 | +//! 3. The third level is the underlying OS error if it is available (e.g. an |
| 17 | +//! `io::Error`) |
| 18 | +//! |
| 19 | +//! For most applications, you'll care only about the first level. For an |
| 20 | +//! example of common error handling dealing only with first level errors, see |
| 21 | +//! [`examples/error-handling-basic.rs`](https://github.com/brannondorsey/mem-isolate/blob/main/examples/error-handling-basic.rs). |
| 22 | +//! |
| 23 | +//! Levels two and three are useful if you want to know more about what |
| 24 | +//! **exactly** went wrong and expose internals about how `mem-isolate` works. |
| 25 | +//! |
| 26 | +//! Note: These errors all describe things that went wrong with a `mem-isolate` |
| 27 | +//! operation. They have nothing to do with the `callable` you passed to |
| 28 | +//! [`crate::execute_in_isolated_process`], which can define its own errors and |
| 29 | +//! maybe values by returning a [`Result`] or [`Option`] type. |
| 30 | +
|
2 | 31 | use serde::Deserialize;
|
3 | 32 | use serde::Serialize;
|
4 | 33 | use std::io;
|
5 | 34 | use thiserror::Error;
|
6 | 35 |
|
7 |
| -// New Error proposal |
8 |
| -#[allow(dead_code)] |
9 |
| -#[allow(clippy::enum_variant_names)] |
| 36 | +/// [`MemIsolateError`] is the **primary error type returned by the crate**. The |
| 37 | +/// goal is to give the caller context about what happened to their callable if |
| 38 | +/// something went wrong. |
10 | 39 | #[derive(Error, Debug, Serialize, Deserialize)]
|
11 | 40 | pub enum MemIsolateError {
|
12 |
| - #[error("an error occurred after the callable was executed: {0}")] |
13 |
| - CallableExecuted(#[source] CallableExecutedError), |
| 41 | + /// Indicates something went wrong before the callable was executed. Because |
| 42 | + /// the callable never executed, it should be safe to naively retry the the |
| 43 | + /// callable with or without mem-isolate, even if the function is not |
| 44 | + /// idempotent. |
14 | 45 | #[error("an error occurred before the callable was executed: {0}")]
|
15 | 46 | CallableDidNotExecute(#[source] CallableDidNotExecuteError),
|
| 47 | + |
| 48 | + /// Indicates something went wrong after the callable was executed. **Do not** |
| 49 | + /// retry execution of the callable unless it is idempotent. |
| 50 | + #[error("an error occurred after the callable was executed: {0}")] |
| 51 | + CallableExecuted(#[source] CallableExecutedError), |
| 52 | + |
| 53 | + /// Indicates something went wrong, but it is unknown wether the callable was |
| 54 | + /// executed. **You should retry the callable only if it is idempotent.** |
16 | 55 | #[error("the callable process exited with an unknown status: {0}")]
|
17 | 56 | CallableStatusUnknown(#[source] CallableStatusUnknownError),
|
18 | 57 | }
|
19 | 58 |
|
| 59 | +// TODO: Document the rest of these errors |
20 | 60 | #[allow(clippy::enum_variant_names)]
|
21 | 61 | #[derive(Error, Debug, Serialize, Deserialize)]
|
22 | 62 | pub enum CallableExecutedError {
|
|
0 commit comments