# Graceful Shutdown (/sdks/ruby/how-to/error-handling/graceful-shutdown)



## Overview [#overview]

A **graceful shutdown** stops a KubeMQ client without dropping in-flight messages or leaking server-side subscription state. Killing a process outright, or closing the client mid-callback, can truncate a handler or leave the server thinking a consumer is still there. In a container platform that sends `SIGTERM` before force-killing a pod, an orderly shutdown sequence turns a rolling deploy into a clean handoff instead of a burst of errors.

The pattern has a fixed order: stop new work by cancelling the subscription, then close the client so remaining resources — gRPC channels, buffers, senders — are released. `CancellationToken#cancel` signals the background subscription thread to stop, `thread.join(3)` waits a bounded interval for that thread to exit, and only then is `client.close` called.

**Gotchas:** calling `client.close` before the thread has joined can race the connection teardown — always cancel and join first. Wrapping the sequence in `ensure` (as this example does) guarantees cleanup still runs if a `KubeMQ::Error` is raised mid-flow; skip it and an exception can orphan the subscription thread.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Ruby SDK installed (`gem install kubemq`)

## Code [#code]

```ruby title="main.rb"
require 'kubemq'

address = ENV.fetch('KUBEMQ_ADDRESS', 'localhost:50000')
channel = 'ruby-error-handling.graceful-shutdown'

begin
  client = KubeMQ::PubSubClient.new(address: address, client_id: 'shutdown-example')
  puts "Connected to #{address}"

  cancel = KubeMQ::CancellationToken.new

  sub = KubeMQ::PubSub::EventsSubscription.new(channel: channel)
  thread = client.subscribe_to_events(sub, cancellation_token: cancel, on_error: ->(e) { puts "Error: #{e.message}" }) do |event|
    puts "Received: #{event.metadata}"
  end
  sleep 1

  puts 'Subscription active, sending events...'
  2.times do |i|
    msg = KubeMQ::PubSub::EventMessage.new(channel: channel, metadata: "shutdown-msg-#{i}", body: "data-#{i}")
    client.send_event(msg)
    sleep 0.2
  end
  sleep 1

  puts 'Cancelling subscription...'
  cancel.cancel
  thread.join(3)
  puts 'Subscription cancelled'

  client.close
  puts 'Client closed — shutdown complete'
rescue KubeMQ::Error => e
  puts "KubeMQ error: #{e.message}"
ensure
  puts 'Done'
end
```

## How It Works [#how-it-works]

* The graceful shutdown sequence: cancel subscriptions, wait for threads to exit, then close the client.
* `CancellationToken.cancel` signals the subscription thread to stop.
* `thread.join(3)` waits up to 3 seconds for the background thread to exit.
* `client.close` releases all remaining resources — gRPC channels, buffers, and senders.
* Review timeouts, channel names, and client IDs before running against shared environments.

## Related [#related]

* [Ruby SDK Reference](/sdks/ruby/reference)
* [Close](/sdks/ruby/how-to/connection/close)
* [Connection Error](/sdks/ruby/how-to/error-handling/connection-error)
