Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drain lock #137

Merged
merged 14 commits into from
Apr 13, 2017
Merged

Drain lock #137

merged 14 commits into from
Apr 13, 2017

Conversation

RemiCardona
Copy link
Contributor

Various spring cleanups and small refactoring that lead to adding a lock around calls to Protocol.drain().

See the links below as to why this is necessary:

AmqpProtocol.close() was quite confusing due to its use of frame.payload
as an argument to AmqpEncoder.  The relationship between the 2 classes
is now much more obvious.
Last user removed in previous commit.
It's used in all user-facing methods, but it's silently ignored by
_write_frame()... so just drop it and let user code handle timeouts if
needed.
With the previous commits, there's only one argument allowed by
_write_frame.  So use it explicitly in _write_frame_awaiting_response's
signature.
Apart from open() where the code is *exactly* the same, the other 3
methods implemented a sub-par version, namely without any error handling
should an exception be raised by _write_frame().

open() and close() set the 'check_open' argument to False because both
methods modify the channel object's state.
There is a danger: if different tasks try to use methods from the same
channel at the same time, there is a risk that publish() and
basic_publish() frames get intertwined with unrelated frames, wreaking
havoc.

But right now, this is impossible because _write_frame isn't a real
coroutine that yields to the main loop.  It's simply a @coroutine-decorated
function.

Also, remove the 'is_open' check because _write_frame does it too.
Except the 2 publish methods, which call drain() explicitly after writing
the 3+ (method, header and body) frames.
@RemiCardona RemiCardona requested review from dzen and rsebille April 10, 2017 22:23
@dzen
Copy link
Contributor

dzen commented Apr 11, 2017

🦭 of approval

@@ -327,7 +333,7 @@ def send_heartbeat(self):
"""
frame = amqp_frame.AmqpRequest(self._stream_writer, amqp_constants.TYPE_HEARTBEAT, 0)
request = amqp_frame.AmqpEncoder()
frame.write_frame(request)
yield from self._write_frame(frame, request)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so calling yield from from a function does NOT work…

Back to the drawing board.

Will be needed in the next commit because write_frame will become a
coroutine.
As of CPython 3.6.1, drain() is not coroutine-safe so put a lock around it
to make sure it only ever gets called from a single coroutine at a time.

http://bugs.python.org/issue29930
python-websockets/websockets#16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants