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
19 changes: 19 additions & 0 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,25 @@ Ably::PubSub::Realtime::Connection::STATE.Connected

`Ably::Rest` and `Ably::Realtime` raise `NameError` in 2.0.

### Releasing realtime channels

In 1.x, `Channels#release` detached a realtime channel before removing it. In 2.0, a realtime channel can only be released
when it is in the `initialized`, `detached` or `failed` state. Releasing it in any other state raises
`Ably::Exceptions::InvalidState` with code `90011`, and the channel is left in place. Detach the channel and wait for the
detach to complete before releasing it:

```ruby
# 1.x
client.channels.release('example')

# 2.0
client.channels.get('example').detach do
client.channels.release('example')
end
```

`Ably::PubSub::Http::Channels#release` is unchanged.

### Unchanged

Everything after construction:
Expand Down
27 changes: 23 additions & 4 deletions core/lib/ably/pubsub/realtime/channels.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,36 @@ def fetch(*args)
super
end

# Detaches the {Ably::PubSub::Realtime::Channel Realtime Channel} and releases all associated resources.
# Releases the {Ably::PubSub::Realtime::Channel Realtime Channel} with the given name and all associated resources.
#
# Releasing a Realtime Channel is not typically necessary as a channel, once detached, consumes no resources other than
# the memory footprint of the {Ably::PubSub::Realtime::Channel Realtime Channel object}. Release channels to free up resources if required
#
# A realtime channel can only be released when it is in the +INITIALIZED+, +DETACHED+, or +FAILED+ state.
#
# @spec RTS4c, RTS4d, RTS4e
#
# @param channel [String] The name of the channel
#
# @raise [Ably::Exceptions::InvalidState] if the channel is not in the +INITIALIZED+, +DETACHED+, or +FAILED+ state
#
# @return [void]
#
def release(channel)
get(channel).detach do
@channels.delete(channel)
end if @channels.has_key?(channel)
return unless @channels.has_key?(channel)

released_channel = get(channel)
unless released_channel.initialized? || released_channel.detached? || released_channel.failed?
raise Ably::Exceptions::InvalidState.new(
"Can only release a channel in a state where there is no possibility of further updates from the server being received " \
"(initialized, detached, or failed). The current state is #{released_channel.state.to_sym}",
400,
90011
)
end

@channels.delete(channel)
nil
end

# Sets channel serial to each channel from given serials hashmap
Expand Down
36 changes: 31 additions & 5 deletions spec/unit/realtime/channels_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,37 @@
end

context 'destroying channels' do
it '#release detaches and then releases the channel resources' do
released_channel = subject.get(channel_name, options)
expect(released_channel).to receive(:detach).and_yield
subject.release(channel_name)
expect(subject.get(channel_name, options).object_id).to_not eql(released_channel.object_id)
let(:released_channel) { subject.get(channel_name, options) }

def stub_state(state)
allow(released_channel).to receive(:state).and_return(Ably::PubSub::Realtime::Channel::STATE(state))
end

it '#release does nothing if the channel does not exist (RTS4c)' do
expect { subject.release(channel_name) }.to_not raise_error
expect(subject.length).to eql(0)
end

[:initialized, :detached, :failed].each do |state|
it "#release releases a channel in the #{state} state without detaching (RTS4d)" do
stub_state state
expect(released_channel).to_not receive(:detach)
subject.release(channel_name)
expect(subject.fetch(channel_name) { nil }).to be_nil
end
end

[:attaching, :attached, :detaching, :suspended].each do |state|
it "#release raises 90011 and leaves a channel in the #{state} state untouched (RTS4e)" do
stub_state state
expect(released_channel).to_not receive(:detach)
expect { subject.release(channel_name) }.to raise_error(Ably::Exceptions::InvalidState) do |error|
expect(error.code).to eql(90011)
expect(error.status).to eql(400)
expect(error.message).to match(/The current state is #{state}/)
end
expect(subject.fetch(channel_name)).to equal(released_channel)
end
end
end

Expand Down
Loading