The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
SafeMapper provides multiple layers of error handling to ensure your long-running computations are robust. This guide covers both the built-in fault tolerance and the explicit error handling functions.
┌─────────────────────────────────────────────────────────────────────────────┐
│ SafeMapper Error Handling Layers │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: Built-in Fault Tolerance │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ • Automatic checkpointing │ │
│ │ • Batch-level retry (configurable attempts) │ │
│ │ • Session recovery on re-run │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ Layer 2: Explicit Error Wrappers │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ s_safely() ──► Capture errors with result/error structure │ │
│ │ s_possibly() ──► Return default value on error │ │
│ │ s_quietly() ──► Capture messages, warnings, output │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ Layer 3: Custom Error Handling │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ tryCatch() within your function │ │
│ │ Conditional logic for expected error cases │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
SafeMapper automatically retries failed batches:
┌─────────────────────────────────────────────────────────────────┐
│ Automatic Retry Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Processing Batch [1-50] │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Attempt 1 │ │
│ │ ├── Success? ─────────────► Save & Continue │
│ │ └── Error? ───────────────┐ │
│ └────────────────────────────┼────────────┘ │
│ │ │
│ ▼ (wait 1s) │
│ ┌─────────────────────────────────────────┐ │
│ │ Attempt 2 │ │
│ │ ├── Success? ─────────────► Save & Continue │
│ │ └── Error? ───────────────┐ │
│ └────────────────────────────┼────────────┘ │
│ │ │
│ ▼ (wait 1s) │
│ ┌─────────────────────────────────────────┐ │
│ │ Attempt 3 (final) │ │
│ │ ├── Success? ─────────────► Save & Continue │
│ │ └── Error? ───────────────► STOP with error │
│ └─────────────────────────────────────────┘ │
│ │
│ Note: Previous batches already saved to checkpoint │
│ On re-run: Resume from last successful batch │
│ │
└─────────────────────────────────────────────────────────────────┘
s_safely() wraps a function to capture errors instead of
throwing them:
# Create a safe version of log
safe_log <- s_safely(log)
# Successful call
result <- safe_log(10)
print(result)
#> $result
#> [1] 2.302585
#>
#> $error
#> NULL
# Error call (returns error instead of throwing)
result <- safe_log("not a number")
print(result)
#> $result
#> NULL
#>
#> $error
#> <simpleError in .f(...): non-numeric argument to mathematical function># Define function that might fail
risky_operation <- function(x) {
if (x < 0) stop("Negative values not allowed")
sqrt(x)
}
# Wrap with s_safely
safe_operation <- s_safely(risky_operation)
# Apply to data that includes problematic values
data <- c(4, -1, 9, -4, 16)
results <- s_map(data, safe_operation)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
# Extract successful results
successes <- s_map_dbl(results, ~ .x$result %||% NA_real_)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(successes)
#> [1] 2 NA 3 NA 4
# Check which failed
errors <- s_map_lgl(results, ~ !is.null(.x$error))
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(errors)
#> [1] FALSE TRUE FALSE TRUE FALSEs_possibly() returns a default value when errors
occur:
# Create a function that returns NA on error
possible_log <- s_possibly(log, otherwise = NA_real_)
# Mix of valid and invalid inputs
inputs <- list(10, "text", 100, NULL, 1000)
results <- s_map_dbl(inputs, possible_log)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(results)
#> [1] 2.302585 NA 4.605170 NA 6.907755# Simulated data extraction that might fail
extract_value <- function(x) {
if (is.null(x) || length(x) == 0) stop("Invalid input")
x[[1]]
}
# Wrap with default value
safe_extract <- s_possibly(extract_value, otherwise = NA)
# Apply to mixed data
data <- list(
list(value = 1),
NULL,
list(value = 3),
list(),
list(value = 5)
)
results <- s_map(data, safe_extract)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(unlist(results))
#> [1] 1 NA 3 NA 5s_quietly() captures messages, warnings, and printed
output:
# Function with side effects
chatty_function <- function(x) {
message("Processing: ", x)
if (x > 5) warning("Large value!")
cat("Result is:", x^2, "\n")
x^2
}
# Wrap with s_quietly
quiet_function <- s_quietly(chatty_function)
# Call it - no output during execution
result <- quiet_function(7)
# Examine captured side effects
print(names(result))
#> [1] "result" "output" "warnings" "messages"
print(result$result)
#> [1] 49
print(result$messages)
#> [1] "Processing: 7\n"
print(result$warnings)
#> [1] "Large value!"
print(result$output)
#> [1] "Result is: 49 "┌─────────────────────────────────────────────────────────────────────────────┐
│ Error Handler Comparison │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Function │ On Error │ Return Structure │ Use Case │
│ ──────────────┼─────────────────┼───────────────────┼──────────────────── │
│ s_safely() │ Captures error │ list(result, │ Need to inspect │
│ │ │ error) │ what went wrong │
│ ──────────────┼─────────────────┼───────────────────┼──────────────────── │
│ s_possibly() │ Returns default │ Same as normal │ Just need results, │
│ │ │ function output │ errors = NA/default │
│ ──────────────┼─────────────────┼───────────────────┼──────────────────── │
│ s_quietly() │ Propagates │ list(result, │ Debug chatty │
│ │ error │ output, │ functions, │
│ │ │ messages, │ capture logs │
│ │ │ warnings) │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
# Best for: When you need to analyze failures
process_item <- function(x) {
if (runif(1) < 0.3) stop("Random failure")
x^2
}
safe_process <- s_safely(process_item)
# Process with checkpointing + error capture
results <- s_map(1:10, safe_process)
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
# Analyze results
success_count <- sum(s_map_lgl(results, ~ is.null(.x$error)))
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
failure_count <- sum(s_map_lgl(results, ~ !is.null(.x$error)))
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
cat("Successes:", success_count, "\n")
#> Successes: 9
cat("Failures:", failure_count, "\n")
#> Failures: 1
# Get successful values
successful_values <- s_map_dbl(results, function(r) {
if (is.null(r$error)) r$result else NA_real_
})
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
print(successful_values)
#> [1] 1 4 9 16 25 NA 49 64 81 100# Best for: When you just need results, failures = NA
robust_sqrt <- s_possibly(
function(x) {
if (x < 0) stop("negative")
sqrt(x)
},
otherwise = NA_real_
)
# Clean pipeline
data <- c(4, -1, 9, -4, 16, -9, 25)
results <- s_map_dbl(data, robust_sqrt)
#> [14%] Processing items 1-7 of 7
#> Completed 7 items
print(results)
#> [1] 2 NA 3 NA 4 NA 5
# Easy to filter out failures
valid_results <- results[!is.na(results)]
print(valid_results)
#> [1] 2 3 4 5# Best for: Critical operations that must not fail
# Layer 1: Function-level error handling
robust_api_call <- function(x) {
tryCatch({
# Simulate API call that might fail
if (runif(1) < 0.2) stop("Temporary failure")
x * 10
}, error = function(e) {
NA_real_ # Return NA on error
})
}
# Layer 2: s_possibly for unexpected errors
safe_api_call <- s_possibly(robust_api_call, otherwise = NA_real_)
# Layer 3: SafeMapper checkpointing
results <- s_map_dbl(
1:20,
safe_api_call,
.session_id = "critical_operation"
)
#> [5%] Processing items 1-20 of 20
#> Completed 20 items
print(results)
#> [1] 10 20 30 40 50 60 70 80 90 100 110 NA 130 NA NA NA 170 180 190
#> [20] 200
cat("Success rate:", mean(!is.na(results)) * 100, "%\n")
#> Success rate: 80 %┌─────────────────────────────────────────────────────────────────────────────┐
│ Which Error Strategy to Use? │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Q: Do you need to know WHY items failed? │
│ │ │
│ ├── YES ──► Use s_safely() │
│ │ Results contain both values and error messages │
│ │ │
│ └── NO ───► Q: Do individual failures matter? │
│ │ │
│ ├── NO ──► Use s_possibly() │
│ │ Clean results, failures become default value │
│ │ │
│ └── YES ─► Use built-in retry │
│ Configure retry_attempts for transient errors │
│ │
│ Q: Need to capture warnings/messages too? │
│ │ │
│ └── YES ──► Use s_quietly() │
│ Captures all side effects for later inspection │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Let errors stop execution immediately (useful during development):
# Create a logging wrapper
log_errors <- function(f) {
function(...) {
tryCatch(
f(...),
error = function(e) {
message("Error: ", e$message)
NA
}
)
}
}
# Use with s_map
logged_sqrt <- log_errors(function(x) {
if (x < 0) stop("negative input")
sqrt(x)
})
results <- s_map_dbl(c(4, -1, 9, -4, 16), logged_sqrt)
#> [20%] Processing items 1-5 of 5
#> Error: negative input
#> Error: negative input
#> Completed 5 items
print(results)
#> [1] 2 NA 3 NA 4# Process and collect all errors
process_with_tracking <- function(items) {
safe_fn <- s_safely(function(x) {
if (x %% 3 == 0) stop("Divisible by 3")
x^2
})
results <- s_map(items, safe_fn)
# Build report
list(
values = s_map(results, "result"),
errors = s_map(results, "error"),
success_rate = mean(s_map_lgl(results, ~ is.null(.x$error)))
)
}
report <- process_with_tracking(1:10)
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
cat("Success rate:", report$success_rate * 100, "%\n")
#> Success rate: 70 %┌─────────────────────────────────────────────────────────────────────────────┐
│ Error Handling Best Practices │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Match Strategy to Need │
│ ├── Development: Let errors propagate (easier debugging) │
│ ├── Production: Use s_safely/s_possibly (robust execution) │
│ └── Critical: Multi-layer protection │
│ │
│ 2. Configure Retries Appropriately │
│ ├── Network operations: 3-5 retries │
│ ├── Local computation: 1 retry (errors usually persistent) │
│ └── Rate-limited APIs: Consider exponential backoff │
│ │
│ 3. Log Errors for Analysis │
│ ├── Use s_safely to capture error details │
│ ├── Store error counts/types for monitoring │
│ └── Alert on error rate thresholds │
│ │
│ 4. Test Error Handling │
│ ├── Intentionally inject failures │
│ ├── Verify checkpoint/recovery works │
│ └── Check that all error cases are handled │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.