Bird
Raised Fist0
NestJSframework~10 mins

Timeout interceptor in NestJS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Timeout interceptor
Request received
↓
Interceptor starts
↓
Start timer
↓
Call next handler
↓
Wait for response or timeout
↓
Response
↓
Send response
↓
Request ends
The interceptor starts a timer, calls the next handler, waits for response or timeout, then either sends the response or throws a timeout error.
Execution Sample
NestJS
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, RequestTimeoutException } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { timeout, catchError } from 'rxjs/operators';

@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      timeout(5000),
      catchError(err => throwError(() => new RequestTimeoutException())),
    );
  }
}
This interceptor sets a 5-second timeout on the request handling observable and throws a timeout exception if exceeded.
Execution Table
StepActionTimer StateNext Handler CalledResponse or TimeoutResult
1Request received, interceptor startsTimer not startedNoNoPrepare to start timer
2Start 5-second timerTimer started (5s)NoNoTimer counting down
3Call next.handle() to process requestTimer runningYesNoWaiting for response or timeout
4Response received before timeoutTimer runningYesResponse receivedSend response to client
5Request endsTimer stoppedYesResponse sentComplete request
6OR timeout reached before responseTimer expiredYesTimeout errorThrow RequestTimeoutException
7Request ends with errorTimer stoppedYesError sentComplete request with error
💡 Execution stops when either response is sent or timeout error is thrown.
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4 or 6Final
timernot startedstarted (5s countdown)runningstoppedstopped
nextHandlerCalledfalsefalsetruetruetrue
responseReceivedfalsefalsefalsetrue or falsetrue or false
timeoutReachedfalsefalsefalsefalse or truefalse or true
Key Moments - 3 Insights
Why does the interceptor use next.handle().pipe() instead of just calling next.handle()?
Because next.handle() returns an observable, and pipe() allows adding operators like timeout and catchError to control the flow and handle timeout errors as shown in execution_table step 3.
What happens if the response takes longer than 5 seconds?
The timeout operator triggers an error, caught by catchError, which throws a RequestTimeoutException as shown in execution_table steps 6 and 7.
Does the timer stop automatically when the response is received?
Yes, when the response arrives before timeout, the timer stops and the response is sent, as shown in execution_table step 5.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, at which step is the next handler called?
AStep 3
BStep 2
CStep 1
DStep 4
💡 Hint
Check the 'Next Handler Called' column in execution_table rows.
According to variable_tracker, what is the state of 'timeoutReached' after step 4?
Atrue
Bfalse
Cundefined
Dnull
💡 Hint
Look at 'timeoutReached' values in variable_tracker after step 4.
If the timeout duration is increased to 10 seconds, how would the execution_table change?
ANext handler would be called twice
BTimer would start after response
CTimeout error would occur later or not at all if response is within 10s
DResponse would be sent immediately
💡 Hint
Consider the 'Timer State' and 'Timeout error' timing in execution_table.
Concept Snapshot
Timeout Interceptor in NestJS:
- Intercepts requests to add a timeout limit
- Uses RxJS operators: timeout() and catchError()
- Throws RequestTimeoutException if exceeded
- Ensures slow requests don't hang forever
- Wraps next.handle() observable with timeout logic
Full Transcript
A Timeout Interceptor in NestJS watches how long a request takes. When a request comes in, the interceptor starts a timer and calls the next handler to process the request. It waits for the response or for the timer to run out. If the response comes before the timer ends, it sends the response back. If the timer runs out first, it throws a timeout error. This helps keep the app responsive by stopping requests that take too long. The interceptor uses RxJS's timeout and catchError operators to manage this flow cleanly.

Practice

(1/5)
1.

What is the main purpose of a TimeoutInterceptor in a NestJS application?

easy
A. To stop requests that take too long and prevent hanging.
B. To log every request made to the server.
C. To cache responses for faster retrieval.
D. To authenticate users before processing requests.

Solution

  1. Step 1: Understand the role of TimeoutInterceptor

    The TimeoutInterceptor is designed to limit how long a request can take before it is stopped.
  2. Step 2: Compare options with the interceptor's purpose

    Only To stop requests that take too long and prevent hanging. describes stopping long requests to avoid hanging, which matches the interceptor's goal.
  3. Final Answer:

    To stop requests that take too long and prevent hanging. -> Option A
  4. Quick Check:

    TimeoutInterceptor stops long requests = D [OK]
Hint: TimeoutInterceptor stops slow requests to keep app responsive [OK]
Common Mistakes:
  • Confusing timeout with logging or caching
  • Thinking it handles authentication
  • Assuming it speeds up all requests
2.

Which of the following is the correct way to apply a timeout of 5 seconds using RxJS timeout operator inside a NestJS interceptor?

return next.handle().pipe( ... )
easy
A. return next.handle().pipe(timeout(500));
B. return next.handle().pipe(timeout(5));
C. return next.handle().pipe(timeout(5000));
D. return next.handle().pipe(timeout(50));

Solution

  1. Step 1: Understand RxJS timeout parameter

    The timeout operator expects time in milliseconds, so 5 seconds is 5000 ms.
  2. Step 2: Match the correct timeout value

    Only return next.handle().pipe(timeout(5000)); uses 5000 which equals 5 seconds; others use incorrect values.
  3. Final Answer:

    return next.handle().pipe(timeout(5000)); -> Option C
  4. Quick Check:

    Timeout in ms for 5 seconds = 5000 [OK]
Hint: Timeout value is always in milliseconds in RxJS [OK]
Common Mistakes:
  • Using seconds instead of milliseconds
  • Using too small timeout values
  • Forgetting to import timeout operator
3.

Given this TimeoutInterceptor code snippet, what will be the output if the request handler takes 7 seconds to respond?

intercept(context, next) {
  return next.handle().pipe(
    timeout(5000),
    catchError(err => throwError(() => new RequestTimeoutException()))
  );
}
medium
A. The request completes successfully after 7 seconds.
B. The request throws a RequestTimeoutException after 5 seconds.
C. The request throws a generic error immediately.
D. The request never completes or errors.

Solution

  1. Step 1: Analyze timeout duration and handler delay

    The timeout is set to 5000 ms (5 seconds), but the handler takes 7 seconds, which is longer.
  2. Step 2: Understand error handling on timeout

    When timeout triggers, catchError throws a RequestTimeoutException, so the request errors after 5 seconds.
  3. Final Answer:

    The request throws a RequestTimeoutException after 5 seconds. -> Option B
  4. Quick Check:

    Handler > timeout triggers RequestTimeoutException = A [OK]
Hint: Timeout triggers error if handler exceeds set milliseconds [OK]
Common Mistakes:
  • Assuming request completes despite timeout
  • Confusing generic error with RequestTimeoutException
  • Ignoring catchError usage
4.

Identify the error in this TimeoutInterceptor implementation:

intercept(context, next) {
  return next.handle().pipe(
    timeout(3000),
    catchError(err => {
      throw new RequestTimeoutException();
    })
  );
}
medium
A. Using throw inside catchError instead of returning an observable error.
B. Timeout value should be in seconds, not milliseconds.
C. Missing import for RequestTimeoutException.
D. The interceptor must return a Promise, not an Observable.

Solution

  1. Step 1: Check error handling inside catchError

    Inside catchError, throwing an error directly breaks the observable chain; it should return an observable error using throwError.
  2. Step 2: Validate other options

    Timeout is correctly in milliseconds, imports are assumed correct, and interceptors return Observables, so only Using throw inside catchError instead of returning an observable error. is the error.
  3. Final Answer:

    Using throw inside catchError instead of returning an observable error. -> Option A
  4. Quick Check:

    Use throwError() inside catchError, not throw [OK]
Hint: Inside catchError, always return throwError() observable [OK]
Common Mistakes:
  • Throwing error directly inside catchError
  • Confusing milliseconds with seconds
  • Assuming interceptors return Promises
5.

You want to create a TimeoutInterceptor that applies a 3-second timeout globally but allows a specific route to override it with a 10-second timeout. Which approach correctly implements this behavior?

hard
A. Set timeout to 10 seconds globally and manually check route inside interceptor to reduce to 3 seconds if needed.
B. Apply two TimeoutInterceptors globally, one with 3 seconds and one with 10 seconds; the last one wins.
C. Create two separate interceptors and apply the 10-second one only on the specific route without global interceptor.
D. Use a global TimeoutInterceptor with 3 seconds and a custom decorator to set metadata for 10 seconds, then read metadata inside the interceptor to override timeout.

Solution

  1. Step 1: Understand global and route-specific timeout needs

    Global interceptor applies 3 seconds by default; specific routes can override by metadata.
  2. Step 2: Implement override using custom decorator and metadata

    Custom decorator sets timeout metadata on route; interceptor reads it and uses that value if present.
  3. Step 3: Evaluate other options

    Applying multiple global interceptors causes conflicts; setting longer timeout globally and reducing for most routes reverses the logic; creating separate interceptors without a global one loses timeout protection on other routes.
  4. Final Answer:

    Use a global TimeoutInterceptor with 3 seconds and a custom decorator to set metadata for 10 seconds, then read metadata inside the interceptor to override timeout. -> Option D
  5. Quick Check:

    Use metadata + decorator to override global timeout [OK]
Hint: Use custom decorator + metadata to override global interceptor timeout [OK]
Common Mistakes:
  • Applying multiple global interceptors causing conflicts
  • Hardcoding timeout values without metadata
  • Not reading route metadata inside interceptor
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard