DEV Community

STOPSIGNAL is now available on Amazon ECS Fargate

Fargate Now Supports “STOP SIGNAL”

https://aws.amazon.com/jp/about-aws/whats-new/2025/12/amazon-ecs-custom-container-stop-signals-fargate/

Fargate now sends the STOPSIGNAL command defined in your Dockerfile to containers.

Why is this great? Previous challenges

Previously, achieving a graceful shutdown on ECS Fargate required creating logic to safely stop after receiving SIGTERM.
https://aws.amazon.com/jp/blogs/news/graceful-shutdowns-with-ecs/

However, middleware often has fixed behavior when receiving a stop signal.
For example, nginx stops immediately upon receiving SIGTERM. This required workarounds like writing trap handling to retry SIGTERM as SIGQUIT.
https://linuxjm.sourceforge.io/html/nginx/man8/nginx.8.html

Improvements

By adhering to the OCI standard, specifying STOPSIGNAL arbitrary_signal in the Dockerfile alone guarantees graceful shutdowns on Fargate, Kubernetes, and local Docker, significantly improving portability.

Why Wasn't This Possible Before? (Analysis)

Fargate likely runs on AWS's proprietary managed host OS (microVM/Firecracker), which may have restricted flexible access. If anyone knows more, please share.

What I Tried

The source for verification is here:
https://github.com/nidcode/ecs-stop-signal-sample

I created a simple program like the one below for testing.

const express = require(‘express’);
const app = express();
const PORT = process.env.PORT || 8080;
const SHUTDOWN_DELAY_MS = parseInt(process.env.SHUTDOWN_DELAY_MS, 10) || 10000;

app.get(‘/’, (req, res) => {
    res.send(‘Running and waiting for stop signal...’);
});

const server = app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

// --- Signal Handler Definition ---
// Handler for SIGTERM (default stop signal)
process.on(‘SIGTERM’, () => {
    handleShutdown(‘SIGTERM’);
});

// Handler for SIGINT (custom verification signal)
process.on(‘SIGINT’, () => {
    handleShutdown(‘SIGINT’);
});

// SIGKILL (force termination) cannot be caught!

function handleShutdown(signal) {
    console.log(`[${signal} RECEIVED] Graceful shutdown initiated.`);

    // 1. Stop accepting new connections to the server
    server.close(() => {
        console.log(‘HTTP server closed.’);
    });

    // 2. Simulate cleanup processes like writing logs and closing the DB
    console.log(`Starting cleanup. Waiting for ${SHUTDOWN_DELAY_MS / 1000} seconds...`);

    // Assumes cleanup completes within the delay period
    setTimeout(() => {
        console.log(`[${signal} SUCCESS] Cleanup complete. Exiting cleanly.`);
        process.exit(0);
    }, SHUTDOWN_DELAY_MS);
}
Enter fullscreen mode Exit fullscreen mode

Test Application Behavior

  • Receives SIGINT and performs cleanup for 10 seconds
  • Records [SIGINT RECEIVED] logs in CloudWatch Logs

For verification, I set the ECS task definition stopTimeout to 15 seconds.

Behavior Without STOPSIGNAL

I added some comments to server.js to create a diff, then ran cdk deploy to force task recreation.

As expected, it receives SIGTERM

Setting STOPSIGNAL

Simply adding STOPSIGNAL to the Dockerfile is sufficient.
Let's configure SIGINT alongside server.js.

FROM node:22-slim
...
STOPSIGNAL SIGINT

CMD [“node”, “server.js”]
Enter fullscreen mode Exit fullscreen mode

Once deployed successfully, run cdk deploy again as before to force the tasks to rebuild.

It caught the SIGINT!

Summary

This custom stop signal support isn't just an added parameter—it signifies that AWS Fargate now fully complies with the international standard for container runtimes (OCI).
This allows container operators to bring standard images used in other environments directly to Fargate, significantly improving deployment and operational quality (Graceful Shutdown).

Top comments (0)