HTTP/2 Priority Tree
Priority is a pure-Python implementation of the HTTP/2 priority logic, as described in RFC 7540 Section 5.3 (Stream Priority). It allows clients to express preferences for how servers allocate resources across concurrent HTTP/2 requests by managing a priority tree. The library uses a variant of the implementation from the H2O project. The current version, 2.0.0, was released in June 2021, indicating a stable project in maintenance mode, part of the broader python-hyper ecosystem for HTTP/2 related libraries.
Common errors
-
ImportError: cannot import name 'PriorityTree' from 'priority'
cause This error occurs when trying to import `PriorityTree` directly from the top-level `priority` module, but the `PriorityTree` class is not directly exposed there. It usually means the import path is incorrect.fixThe `PriorityTree` class is typically accessed after importing the `priority` package. The correct way to use it is by instantiating it after `import priority` or by using `from priority.tree import PriorityTree` if specifically importing the class. -
priority.exceptions.DuplicateStreamError: An attempt was made to insert a stream that already exists.
cause This error is raised when `insert_stream()` is called with a `stream_id` that is already present in the `PriorityTree`. HTTP/2 stream IDs must be unique within a connection.fixEnsure that each stream inserted into the `PriorityTree` has a unique `stream_id`. If a stream's priority needs to be updated, use the `reprioritize()` method instead of `insert_stream()`. -
priority.exceptions.MissingStreamError: An operation was attempted on a stream that is not present in the tree.
cause This exception occurs when methods like `block()`, `unblock()`, `reprioritize()`, or `remove_stream()` are called with a `stream_id` that does not exist in the `PriorityTree`.fixVerify that the `stream_id` passed to the method corresponds to an existing stream in the `PriorityTree`. Ensure the stream has been previously inserted and not yet removed. -
priority.exceptions.TooManyStreamsError: An attempt was made to insert a dangerous number of streams into the priority tree at the same time.
cause This error indicates that the maximum allowed number of streams in the `PriorityTree` has been exceeded. The library has a default limit (e.g., 1000) to prevent denial-of-service attacks by malicious peers.fixThis often points to an issue with managing stream lifecycle. Ensure streams are correctly removed using `remove_stream()` when they are no longer needed. If a higher limit is genuinely required, the `maximum_streams` parameter can be set during `PriorityTree` initialization, e.g., `p = priority.PriorityTree(maximum_streams=2000)` (though this should be done cautiously). -
AttributeError: 'PriorityTree' object has no attribute 'some_non_existent_method'
cause This is a general Python error indicating that an attribute or method being called does not exist on the `PriorityTree` object. This typically happens due to typos or incorrect assumptions about the library's API.fixConsult the `priority` library's documentation for the correct method names and their usage. For example, if intending to block a stream, use `p.block(stream_id)` instead of a misspelled or non-existent method.
Warnings
- gotcha HTTP/2 stream prioritization is a suggestion to the server, not a strict command. Servers and intermediate network elements (like proxies or CDNs) may not fully respect client-side priority requests due to their own implementation details, buffering, or policy, potentially leading to resource allocation that doesn't match client expectations.
- gotcha The `PriorityTree`'s effectiveness relies on accurate and timely updates of stream states. Failing to call methods like `block(stream_id)` when a stream is unable to send data, or `unblock(stream_id)` when it becomes active again, can lead to suboptimal or stalled resource allocation.
Install
-
pip install priority
Imports
- PriorityTree
from priority import PriorityTree
Quickstart
import priority
p = priority.PriorityTree()
p.insert_stream(stream_id=1)
p.insert_stream(stream_id=3)
p.insert_stream(stream_id=5, depends_on=1)
p.insert_stream(stream_id=7, weight=32)
p.insert_stream(stream_id=9, depends_on=7, weight=8)
p.insert_stream(stream_id=11, depends_on=7, exclusive=True)
# Simulate sending data by iterating the tree
print("Initial serving order:")
for _ in range(10):
next_stream_id = p.next_stream_to_send()
if next_stream_id is None:
print(" No more active streams.")
break
print(f" Sending data for stream: {next_stream_id}")
# Simulate blocking a stream after it's been served once
if next_stream_id == 7:
p.block(7)
print(" Stream 7 blocked for demonstration.")
# Unblock a stream to see it re-enter the queue
p.unblock(7)
print("\nStream 7 unblocked. Continuing serving order:")
for _ in range(5):
next_stream_id = p.next_stream_to_send()
if next_stream_id is None:
print(" No more active streams.")
break
print(f" Sending data for stream: {next_stream_id}")