Problem: Decorate a Retryable Operation with Metrics
Problem statement
You’re responsible for stabilizing a service call that occasionally fails due to random network errors. Your task is twofold: first, implement a retry wrapper that automatically retries failed async operations. Then, use decorators to add observability—logging and timing—without changing the retry logic.
This simulates real-world resilience patterns where we layer monitoring on top of recovery mechanisms.
Goal
Implement a
retry(fn)function that:Calls
fn()up to 3 times.Retries only when an error is thrown.
Returns the first successful result.
Throws the last error after 3 failed attempts.
Implement two decorators:
withLogging(fn): Logs when the operation starts and whether it succeeded or failed.withTiming(fn): Measures the time it takes for the operation (including retries).
Compose them together:
const wrappedOperation = withTiming(withLogging(retry(flakyOperation)));
Constraints
Do not modify
flakyOperation.The
retry,withLogging, andwithTimingfunctions must be independent.Handle errors gracefully and log retries.
Use only
console.logfor all output.
Sample output
The examples below illustrate what the output should look like:
(async () => {const wrappedOperation = withTiming(withLogging(retry(flakyOperation)));try {const result = await wrappedOperation();console.log('Final Result:', result);} catch (err) {console.log('Operation failed after retries');}})();/* Expected output (might vary):[LOG] Starting operation...[RETRY] Attempt 1 failed[RETRY] Attempt 2 failed[LOG] Operation succeeded[TIMER] retry took 312msFinal Result: Success! */
Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.
Problem: Decorate a Retryable Operation with Metrics
Problem statement
You’re responsible for stabilizing a service call that occasionally fails due to random network errors. Your task is twofold: first, implement a retry wrapper that automatically retries failed async operations. Then, use decorators to add observability—logging and timing—without changing the retry logic.
This simulates real-world resilience patterns where we layer monitoring on top of recovery mechanisms.
Goal
Implement a
retry(fn)function that:Calls
fn()up to 3 times.Retries only when an error is thrown.
Returns the first successful result.
Throws the last error after 3 failed attempts.
Implement two decorators:
withLogging(fn): Logs when the operation starts and whether it succeeded or failed.withTiming(fn): Measures the time it takes for the operation (including retries).
Compose them together:
const wrappedOperation = withTiming(withLogging(retry(flakyOperation)));
Constraints
Do not modify
flakyOperation.The
retry,withLogging, andwithTimingfunctions must be independent.Handle errors gracefully and log retries.
Use only
console.logfor all output.
Sample output
The examples below illustrate what the output should look like:
(async () => {const wrappedOperation = withTiming(withLogging(retry(flakyOperation)));try {const result = await wrappedOperation();console.log('Final Result:', result);} catch (err) {console.log('Operation failed after retries');}})();/* Expected output (might vary):[LOG] Starting operation...[RETRY] Attempt 1 failed[RETRY] Attempt 2 failed[LOG] Operation succeeded[TIMER] retry took 312msFinal Result: Success! */
Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.