Skip to content

[RFC]: Lazy state changes. #228

Open
@Lukasa

Description

@Lukasa

Inspired by @njsmith in njsmith/h11#4.

Right now there is a wart in the h2 API when working on a busy connection. The problem exists when working with receive_data. For example, it is possible that you might encounter the following set of events returned from receive_data: [DataReceived(stream_id=1), WindowUpdated(stream_id=1), StreamReset(stream_id=1)].

In response to that WindowUpdated you may want to send another data frame on stream 1, but if you do so without processing the entire event list h2 will throw a ProtocolError at you because the stream is now in the CLOSED state. However, the user doesn't know that: they're processing the events serially, and haven't gotten to the event that actually closed the stream.

The outcome of this is not too bad: while the ProtocolError does get thrown, the connection state is still fine and no damage has been done to your ability to continue to use the connection. However, the exception may cause an incautious user to run into trouble: if they're not expecting and handling this exception it'll quite probably cause them to lose a lot of application state.

In njsmith/h11#4, @njsmith has proposed a split API for receiving data: a single receive_data call returns no events, but instead you need to call next_event to advance the state machine. This proposal is essentially a "split" API much like we have for sending.

Making that change is a pretty substantial API change and I don't know how I feel about it. However, it turns out that hyper-h2 is capable of emulating that change with a very simple change to the logic of receive_data.

Right now, receive_data returns a list of events. However, it would be a trivial change for receive_data to return a generator instead. That generator would then iterate across events, one event at a time. The effect of doing that would be to avoid updating the state machines until the user has an event in hand, and would essentially immediately change hyper-h2 to an API that lazily updates stream state. This would ensure that a user cannot see a ProtocolError for sending data on a closed stream unless they have iterated past an event that closed the stream (or they closed it themselves).

I'm interested in what @python-hyper/contributors think, as well as our wider user-base. I think making such a change would be extremely valuable, but it represents a breaking API change (receive_data is documented as returning a list).

Do people think this change is sensible?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions