Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,72 @@ However, the recommendation is to always use `start_link/3` and if necessary tra

This is because `start/3` creates a detached process and has the capability to produce zombie processes outside of any
application tree. This is generally a good piece of advice for any process, however since a module using WebSockex
bevhaviour can be written as a self-sustaining tcp connection. I feel like it is even more important to express this
behaviour can be written as a self-sustaining tcp connection. I feel like it is even more important to express this
particular piece of advice here.

## Closing Connections

WebSockex provides several ways to close a WebSocket connection gracefully. Most of the callback functions support returning close tuples to initiate connection closure.

### Basic Close

The simplest way to close a connection is to return `{:close, state}` from any of the following callbacks:
- `handle_frame/2`
- `handle_cast/2`
- `handle_info/2`
- `handle_ping/2`
- `handle_pong/2`

```elixir
def handle_frame({:text, "shutdown"}, state) do
{:close, state}
end

def handle_cast(:close, state) do
{:close, state}
end
```

This will close the connection with the default close code `1000` (normal closure).

### Close with Custom Code and Reason

You can also specify a custom close code and reason message by returning `{:close, {close_code, message}, state}`:

```elixir
def handle_frame({:text, "error"}, state) do
{:close, {4000, "Custom application error"}, state}
end
```

Valid close codes are integers in specific ranges:
- `1000-1015` - Standard protocol codes (e.g., 1000 = normal, 1001 = going away, 1002 = protocol error, 1003 = unsupported data)
- `3000-3999` - Reserved for use by libraries, frameworks, and applications (registered with IANA)
- `4000-4999` - Private use for applications

Some common standard codes include:
- `1000` - Normal closure
- `1001` - Going away
- `1002` - Protocol error
- `1003` - Unsupported data

### Programmatic Close via Cast

You can also close the connection by sending a cast message to the WebSockex process:

```elixir
# In your client module
def close(pid) do
WebSockex.cast(pid, :close)
end

def handle_cast(:close, state) do
{:close, state}
end
```

See the `examples/echo_client.exs` for a working example of connection closure.

## Telemetry

Websockex clients emit the following telemetry events:
Expand Down
42 changes: 42 additions & 0 deletions lib/websockex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,48 @@ defmodule WebSockex do
end
```

## Closing Connections

WebSockex connections can be closed gracefully by returning close tuples from
callback functions. The following callbacks support close returns:

- `c:handle_frame/2`
- `c:handle_cast/2`
- `c:handle_info/2`
- `c:handle_ping/2`
- `c:handle_pong/2`

### Basic Close

Return `{:close, state}` to close with the default close code (1000):

```
def handle_frame({:text, "quit"}, state) do
{:close, state}
end
```

### Close with Custom Code

Return `{:close, {close_code, message}, state}` to specify a close code and reason:

```
def handle_frame({:text, "error"}, state) do
{:close, {4000, "Application error"}, state}
end
```

Close codes are integers in specific ranges:
- `1000-1015` - Standard protocol codes (e.g., 1000 = normal, 1001 = going away, 1002 = protocol error, 1003 = unsupported data)
- `3000-3999` - Reserved for use by libraries, frameworks, and applications (registered with IANA)
- `4000-4999` - Private use for applications

Common standard codes include:
- `1000` - Normal closure
- `1001` - Going away
- `1002` - Protocol error
- `1003` - Unsupported data

## Supervision

WebSockex is implemented as an OTP Special Process and as a result will fit
Expand Down