Bird
Raised Fist0
Denoframework~10 mins

Signal handling and process management in Deno - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Signal handling and process management
Start Program
↓
Register Signal Handler
↓
Wait for Signal or Event
↓
Signal Received?
No→Continue Running
Yes↓
Execute Signal Handler
↓
Perform Cleanup or Actions
↓
Exit or Resume Program
The program starts, sets up a signal handler, waits for signals, and when a signal arrives, runs the handler to manage process cleanup or actions.
Execution Sample
Deno
import { signal } from "https://deno.land/std/signals/mod.ts";

const sig = signal("SIGINT");

for await (const _ of sig) {
  console.log("SIGINT received, exiting...");
  Deno.exit();
}
This code listens for the SIGINT signal (Ctrl+C). When received, it prints a message and exits the program.
Execution Table
StepActionSignal EventOutputProgram State
1Import signal moduleNoneReady to listen
2Create signal listener for SIGINTNoneListening for SIGINT
3Start for-await loop waiting for SIGINTNoneWaiting for signal
4User presses Ctrl+CSIGINT receivedSignal detected
5Inside loop: print messageSIGINT receivedSIGINT received, exiting...Handling signal
6Call Deno.exit()SIGINT receivedProgram exits
7Program terminatesNoneStopped
💡 Program exits after handling SIGINT signal with Deno.exit()
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4Final
sigundefinedSignalListener for SIGINTSignalListener for SIGINTSignalListener triggeredProgram exited
Key Moments - 3 Insights
Why does the program wait indefinitely at the for-await loop?
Because the for-await loop listens asynchronously for the SIGINT signal and pauses execution until the signal arrives, as shown in execution_table step 3.
What happens if the signal is never received?
The program stays waiting inside the for-await loop indefinitely, continuing to listen without exiting, as seen in execution_table steps 3 and 7.
Why do we call Deno.exit() inside the signal handler?
To stop the program immediately after handling the signal, preventing further code execution, as shown in execution_table step 6.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the program state at step 4?
AProgram exited
BWaiting for signal
CSignal detected
DReady to listen
💡 Hint
Check the 'Program State' column at step 4 in the execution_table.
At which step does the program print the message 'SIGINT received, exiting...'?
AStep 5
BStep 3
CStep 4
DStep 6
💡 Hint
Look at the 'Output' column in the execution_table to find when the message appears.
If we remove Deno.exit() from the code, what would happen after receiving SIGINT?
AProgram exits immediately
BProgram continues running and waits for next signal
CProgram crashes
DSignal is ignored
💡 Hint
Refer to the key_moments section about the role of Deno.exit() and execution_table step 6.
Concept Snapshot
Signal handling in Deno uses async iteration over signals.
Use 'signal("SIGINT")' to listen for Ctrl+C.
The for-await loop waits for signals asynchronously.
Inside the loop, handle signals (e.g., cleanup, exit).
Call Deno.exit() to stop the program after handling.
Without exit, program keeps running and listening.
Full Transcript
This lesson shows how Deno programs handle signals like SIGINT (Ctrl+C). The program imports the signal module and creates a listener for SIGINT. It then waits asynchronously in a for-await loop for the signal. When the user presses Ctrl+C, the signal is detected, the program prints a message, and calls Deno.exit() to stop. If no signal arrives, the program waits indefinitely. Removing Deno.exit() means the program would continue running and listening for more signals. This pattern helps manage process cleanup and graceful shutdowns.

Practice

(1/5)
1. What is the main purpose of signal handling in a Deno program?
easy
A. To respond to system events like Ctrl+C or termination requests
B. To speed up the execution of asynchronous code
C. To automatically restart the program after an error
D. To manage memory allocation for the program

Solution

  1. Step 1: Understand what signals are

    Signals are system messages sent to a program, such as when a user presses Ctrl+C.
  2. Step 2: Identify signal handling purpose

    Signal handling lets the program catch these signals and respond, for example, to clean up resources before exiting.
  3. Final Answer:

    To respond to system events like Ctrl+C or termination requests -> Option A
  4. Quick Check:

    Signal handling = respond to system events [OK]
Hint: Signals catch system events like Ctrl+C to handle them [OK]
Common Mistakes:
  • Confusing signal handling with error handling
  • Thinking signal handling speeds up code
  • Assuming signals manage memory automatically
2. Which of the following is the correct way to listen for a SIGINT signal in Deno?
easy
A. Deno.listenSignal('SIGINT', () => console.log('Interrupted'))
B. Deno.signal(Deno.Signal.SIGINT).then(() => console.log('Interrupted'))
C. Deno.on('SIGINT', () => console.log('Interrupted'))
D. for await (const _ of Deno.signal(Deno.Signal.SIGINT)) { console.log('Interrupted') }

Solution

  1. Step 1: Recall Deno's signal API usage

    Deno.signal returns an async iterable for the given signal.
  2. Step 2: Identify correct syntax to listen continuously

    Using a for-await-of loop over Deno.signal(Deno.Signal.SIGINT) listens repeatedly for SIGINT events.
  3. Final Answer:

    for await (const _ of Deno.signal(Deno.Signal.SIGINT)) { console.log('Interrupted') } -> Option D
  4. Quick Check:

    Use for-await-of with Deno.signal for signals [OK]
Hint: Use for-await-of loop with Deno.signal to handle signals [OK]
Common Mistakes:
  • Using .then() which only handles one signal once
  • Trying to use event emitter style which Deno does not support
  • Using non-existent Deno.listenSignal method
3. What will the following Deno code output when you press Ctrl+C once?
const sig = Deno.signal(Deno.Signal.SIGINT);
for await (const _ of sig) {
  console.log('Signal received');
  sig.dispose();
}
medium
A. Signal received (printed once), then program stops listening for SIGINT
B. SyntaxError because dispose() cannot be called inside loop
C. Signal received printed repeatedly on every Ctrl+C press
D. Signal received (printed once), then program continues running

Solution

  1. Step 1: Understand the for-await-of loop over signal

    The loop waits for SIGINT signals and runs the body each time one occurs.
  2. Step 2: Effect of calling sig.dispose()

    Calling dispose() stops the signal listener, so after the first Ctrl+C, the loop ends and no more signals are handled.
  3. Final Answer:

    Signal received (printed once), then program stops listening for SIGINT -> Option A
  4. Quick Check:

    dispose() stops signal listening after first event [OK]
Hint: dispose() stops signal listening; loop ends after first signal [OK]
Common Mistakes:
  • Thinking dispose() only pauses temporarily
  • Assuming the loop continues printing on every Ctrl+C
  • Believing dispose() causes syntax errors
4. Identify the error in this Deno code snippet that tries to spawn a child process and handle its exit:
const p = Deno.run({ cmd: ["ls", "-l"] });
p.status().then(status => {
  console.log(`Process exited with code ${status.code}`);
});
p.close();
medium
A. Deno.run does not exist; should use Deno.spawn instead
B. Missing await before p.status() causes unhandled promise
C. Calling p.close() before the process finishes causes resource leaks
D. The cmd array should be a string, not an array

Solution

  1. Step 1: Understand process lifecycle in Deno

    Deno.run starts a child process and returns a process handle.
  2. Step 2: Analyze order of close() call

    Calling p.close() immediately releases resources before the process finishes, which can cause issues.
  3. Final Answer:

    Calling p.close() before the process finishes causes resource leaks -> Option C
  4. Quick Check:

    Close process handle only after process ends [OK]
Hint: Call close() only after process completes to avoid leaks [OK]
Common Mistakes:
  • Calling close() too early before process ends
  • Confusing Deno.run with Deno.spawn (spawn is newer API)
  • Thinking cmd should be a string instead of array
5. You want to write a Deno script that runs a child process and gracefully handles Ctrl+C to kill the child before exiting. Which approach correctly combines signal handling and process management?
hard
A. Call child.kill() immediately after spawning, then listen for SIGINT to exit
B. Use for-await-of on Deno.signal(Deno.Signal.SIGINT) to catch Ctrl+C, then call child.kill() and await child.status() before exiting
C. Use Deno.run with cmd and ignore signals; rely on OS to kill child on exit
D. Spawn child process with Deno.spawn and never call kill(), just exit on SIGINT

Solution

  1. Step 1: Understand graceful shutdown

    On Ctrl+C, the program should catch SIGINT and clean up child processes before exiting.
  2. Step 2: Combine signal listening and child process control

    Using for-await-of on Deno.signal(Deno.Signal.SIGINT) allows catching Ctrl+C; then calling child.kill() stops the child, and awaiting child.status() ensures it ends cleanly.
  3. Final Answer:

    Use for-await-of on Deno.signal(Deno.Signal.SIGINT) to catch Ctrl+C, then call child.kill() and await child.status() before exiting -> Option B
  4. Quick Check:

    Signal handling + kill child + await status = graceful exit [OK]
Hint: Catch SIGINT, kill child, await status for clean exit [OK]
Common Mistakes:
  • Killing child before signal received
  • Ignoring signals and leaving child running
  • Not awaiting child.status() causing premature exit
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