# Releases

## v0.37.0

  - Rename `ASYNC_CONTAINER_GRACEFUL_TIMEOUT` to `ASYNC_CONTAINER_GRACEFUL_STOP` and apply it at the controller level as `GRACEFUL_STOP`. `Group#stop` now only applies the shutdown policy it is given.

## v0.36.0

  - Forked containers now fork child processes from a short-lived thread, reducing inherited scheduler and parent stack state in children.

## v0.35.1

  - **Fixed**: `Hybrid` container now stops on interrupt instead of restarting indefinitely.

## v0.35.0

  - **Fixed**: `Hybrid` now interrupts inner threaded children during graceful shutdown and force-stops remaining children on exit.

## v0.34.5

  - **Fixed**: `instance.exec` with `ready: true` no longer causes premature termination. The notification pipe is now always passed to the exec'd process.

## v0.34.4

  - Add missing `bake` and `context` files to the release.

## v0.34.3

  - `Controller#restart` and `Controller#reload` now include a `status:` message in the `ready!` notification, so `systemctl status` shows "Running with N children." instead of the stale "Initializing controller..." message.

## v0.34.2

  - Once a container is stopped, it stays stopped.

## v0.34.0

  - Add `Async::Container::Generic#stopping?` so that policies can more accurately track the state of the container.

## v0.33.0

  - Add `Policy#make_statistics` to allow policies to customize statistics initialization.

## v0.32.1

  - Expose `Async::Container::Controller` `#notify`, `#container_class`, and `#graceful_stop` for testing.

## v0.32.0

  - Minor **breaking** changes to `Async::Container::Policy` interface.
  - Expose `Async::Container::Statistics::Rate#window`.

## v0.31.0

  - Introduce `Async::Container::Policy` for managing child lifecycle events and implementing custom failure handling strategies.
  - Add `Async::Container::Statistics::Rate` for tracking failure and restart rates over sliding time windows.
  - Fix restart counter to only increment when actually restarting (check `@running` flag).

## v0.30.0

  - `SIGTERM` is now graceful, the same as `SIGINT`, for better compatibility with Kubernetes and systemd.
  - `ASYNC_CONTAINER_INTERRUPT_TIMEOUT` and `ASYNC_CONTAINER_TERMINATE_TIMEOUT` are removed and replaced by `ASYNC_CONTAINER_GRACEFUL_TIMEOUT`.

## v0.29.0

  - Introduce `Client#healthy!` for sending health check messages.

## v0.28.0

  - Add `startup_timeout` parameter to `spawn` and `run` methods for detecting processes that hang during startup and never become ready.
  - Health check timeout now only applies after a process becomes ready, preventing premature timeouts for slow-starting applications.

## v0.27.5

  - Make the child handling more robust in the face of exceptions.

## v0.27.4

  - Fix race condition where `wait_for` could modify `@running` while it was being iterated over (`each_value`) during health checks.

## v0.27.3

  - Add log for starting child, including container statistics.
  - Don't try to (log) "terminate 0 child processes" if there are none.

## v0.27.2

  - More logging, especially around failure cases.

## v0.27.1

  - Log caller and timeout when waiting on a child instance to exit, if it blocks.

## v0.27.0

  - Increased default interrupt timeout and terminate timeout to 10 seconds each.
  - Expose `ASYNC_CONTAINER_INTERRUPT_TIMEOUT` and `ASYNC_CONTAINER_TERMINATE_TIMEOUT` environment variables for configuring default timeouts.

## v0.26.0

### Production Reliability Improvements

This release significantly improves container reliability by eliminating production hangs caused by unresponsive child processes.

**SIGKILL Fallback Support**: Containers now automatically escalate to SIGKILL when child processes ignore SIGINT and SIGTERM signals. This prevents the critical production issue where containers would hang indefinitely waiting for uncooperative processes to exit.

**Hang Prevention**: Individual child processes now have timeout-based hang prevention. If a process closes its notification pipe but doesn't actually exit, the container will detect this and escalate to SIGKILL after a reasonable timeout instead of hanging forever.

**Improved Three-Phase Shutdown**: The `Group#stop()` method now uses a cleaner interrupt → terminate → kill escalation sequence with configurable timeouts for each phase, giving well-behaved processes multiple opportunities to shut down gracefully while ensuring unresponsive processes are eventually terminated.

## v0.25.0

  - Introduce `async:container:notify:log:ready?` task for detecting process readiness.

## v0.24.0

  - Add support for health check failure metrics.

## v0.23.0

### Add support for `NOTIFY_LOG` for Kubernetes readiness probes.

You may specify a `NOTIFY_LOG` environment variable to enable readiness logging to a log file. This can be used for Kubernetes readiness probes, e.g.

``` yaml
containers:
	- name: falcon
		env:
			- name: NOTIFY_LOG
				value: "/tmp/notify.log"
		command: ["falcon", "host"]
		readinessProbe:
			exec:
				command: ["sh", "-c", "grep -q '\"ready\":true' /tmp/notify.log"]
			initialDelaySeconds: 5
			periodSeconds: 5
			failureThreshold: 12
```

## v0.21.0

  - Use `SIGKILL`/`Thread#kill` when the health check fails. In some cases, `SIGTERM` may not be sufficient to terminate a process because the signal can be ignored or the process may be in an uninterruptible state.

## v0.20.1

  - Fix compatibility between {ruby Async::Container::Hybrid} and the health check.
  - {ruby Async::Container::Generic\#initialize} passes unused arguments through to {ruby Async::Container::Group}.

## v0.20.0

  - Improve container signal handling reliability by using `Thread.handle_interrupt` except at known safe points.
  - Improved logging when child process fails and container startup.

### Add `health_check_timeout` for detecting hung processes.

In order to detect hung processes, a `health_check_timeout` can be specified when spawning children workers. If the health check does not complete within the specified timeout, the child process is killed.

``` ruby
require "async/container"

container = Async::Container.new

container.run(count: 1, restart: true, health_check_timeout: 1) do |instance|
	while true
		# This example will fail sometimes:
		sleep(0.5 + rand)
		instance.ready!
	end
end

container.wait
```

If the health check does not complete within the specified timeout, the child process is killed:

``` 
 3.01s     warn: Async::Container::Forked [oid=0x1340] [ec=0x1348] [pid=27100] [2025-02-20 13:24:55 +1300]
               | Child failed health check!
               | {
               |   "child": {
               |     "name": "Unnamed",
               |     "pid": 27101,
               |     "status": null
               |   },
               |   "age": 1.0612829999881797,
               |   "health_check_timeout": 1
               | }
```
