[adr] Network async/event API proposal - #17685
Conversation
PR Summary by QodoADR: Define network handler disposition, ordering, and failure semantics Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
1.
|
b09a2bc to
18895d1
Compare
|
Code review by qodo was updated up to the latest commit 18895d1 |
diemol
left a comment
There was a problem hiding this comment.
I think this ADR will help us unify handler behavior across all language bindings, which is currently handled differently in each language.
If I understand this correctly, @titusfortner suggests this ADR is an alternative to #17671. But what I see is that this ADR covers network interception, which blocks because it waits for a handler disposition. Whereas #17671 is about observation, which should not block, and only subscribes to events (did I get that right, @AutomatedTester?).
That is why I believe the two ADRs complement each other.
In addition, this ADR, like #17671, seems to me to be a middle-layer API. One that users would use for specific use cases that the high-level API won't cover.
In the last TLC meeting people were pushing for the idea that for now everything that can block will block in our implementations and we won't handle it any differently. I'm saying they are in opposition because if you adopt this ADR, you don't need the extra methods proposed by the other ADR. Also, I think it is wrong to characterize these as "middle-layer API." Anything that affects the code the user needs to write is user-facing and needs to be part of the high-level API contract we are creating that we want to maintain. |
The way I see these two ADRs:
That's why I think there are two other options: either observe or intercept here. I still think that this is a middle-layer API. I don't want the user to have to handle all these callbacks and other things to manipulate their code in BiDi. I want this API to land and be used in a higher-level API to do network routing, mocking, and method interception, covering all of this implementation. In my head, we should have:
If this current ADR is what we're doing at the high level, it is way too complex. |
|
Code review by qodo was updated up to the latest commit 281e9bb |
|
Code review by qodo was updated up to the latest commit 895d532 |
Can we get the functionality implemented across the bindings then figure out which wrappers and helpers and fixtures to add later? I feel like we may need to step back from the ADRs and agree to the milestones and requirements for Selenium 5 again. |
This is confusing because my interpretation is that the
I think this bit is what #17671 and this ADR need to agree on. That is the foundation for both.
I am calling it a middle layer, which is core to what we want to achieve, because when I check Playwright's API, I see a high-level API that lets users handle less. But I think you have a point: landing all this "first and later" about major abstractions. |
Based on your questions it didn't seem like you understood my intention for including it or how it worked (it was never blocking anything, there was nothing in the lambda that needed resolving or a true state), so it seemed distracting from what I consider to be the primary things I want us to agree on. Essentially 17671 and the "complete" method are 2 different ways to manage a wrapper around behavior the user can already easily do themselves for network calls. Is it actually a priority to provide convenience methods to replaces those 4 lines? When I started thinking in those terms I decided that we don't need wrapper behavior right now, so if I want to reject 17671 on that basis, I should also reject my "complete" method. If we decide we want wrapper behavior, then I would still prefer "complete" over "expect_*" But also it feels like we're arguing over implementation details of a concept we haven't even agreed is behavior we need right now, so I also want to be able to step back one level on it. For instance, I don't think "how to differentiate between observation and interception" is actually fundamental to any of our other conversations. The TLC meeting 2 weeks ago the general consensus from everyone else was to defer this decision until later because "intercept everything for now" works well enough for most things. I'd rather hammer it out now, but I'm fine with pushing it off. I only added it here to show that supporting it isn't a sufficient reason on its own to expand the API and accept 17671. |
895d532 to
2d7b847
Compare
|
Code review by qodo was updated up to the latest commit 2d7b847 |
There was a problem hiding this comment.
Pull request overview
This pull request introduces a new Architecture Decision Record (ADR) defining the intended cross-binding behavior of Selenium’s protocol-neutral driver.network async/event handler API, specifically how request/response/authentication handlers are registered and how they compose when multiple handlers match.
Changes:
- Adds an ADR specifying handler registration (add/remove/clear), scoping via structured URL-pattern components, and handler execution ordering (LIFO).
- Defines observation vs interception mode semantics, disposition resolution (first to settle stops the chain), and default “fall through” behavior.
- Specifies exception handling semantics and opt-in body collection behavior.
Code Review by Qodo
1.
|
|
Code review by qodo was updated up to the latest commit 0f9f79c |
|
Code review by qodo was updated up to the latest commit 887ad3c |
|
Code review by qodo was updated up to the latest commit 7fd4917 |
|
Code review by qodo was updated up to the latest commit 1d78efe |
…ome unspecified on handler throw
|
Code review by qodo was updated up to the latest commit 0e068c9 |
| By default, a handler blocks the event until it has run. The decisions below can be implemented in | ||
| more than one way; the Ruby and Java examples show the user-facing shape, not a prescribed API. | ||
|
|
||
| 1. **Handlers can be added, removed, and cleared.** Each family — request, |
There was a problem hiding this comment.
This is push based mechanism. I agree it should be blocked/ordered. Not yet clear if handler fails occasionally, then what (in .NET I fail fast, stop delivering, reveal at the end)?
Additionally I propose pull based events. Already in .NET:
await using var stream = await bidi.Network.BeforeRequestSent.StreamAsync();
// do something
// stop stream (via dispose)
// magic I am sure available in any binding
var allNotFoundImageUrls = await stream.Where(r => r.Status == 404 && r.Url.EndsWith("png")).Select(r => r.Url).ToListAsync();This is amazing API for free - async enumeration.
There was a problem hiding this comment.
On failure: Good question. What's in the ADR isn't exactly what I thought. User must handle exceptions themselves. Unhandled exceptions are propagated to the user, but do not automatically stop the session. It should be possible for a user to have code that can catch an exception from the main thread still. The ADR currently says other handlers will process the event, but I think we need to change it so that the event stops being processed if there is an error, and the event is submitted. I'll bring this up at the next TLC meeting.
I like it pull-based streaming but, but it fits observation approach, and doesn't really work for interception, and async-enumeration only works with an async/await solution which isn't available for several of the bindings, so it can't be part of the shared contract.
…ern passthrough, context scoping, request-only body collection
…ncaught exception
| 11. **Handlers are scoped to the current browsing context by default.** A handler applies to the | ||
| browsing context that is active when it is registered, resolved from the current window; the user | ||
| may pass a browsing context, a user context, or both to scope it elsewhere. This lets a handler | ||
| apply to a context that is not the active one, such as a background tab that does not currently |
There was a problem hiding this comment.
2. Context scoping rules undefined 🐞 Bug ⚙ Maintainability
Decision 11 allows scoping a handler by browsing context, user context, or both, but does not define how providing both combines (AND vs precedence vs union) or what happens when the provided contexts conflict, which will produce incompatible interception scopes across bindings.
Agent Prompt
## Issue description
Decision 11 explicitly permits passing a browsing context, a user context, or both, but does not define the required semantics when both are provided or when they disagree.
## Issue Context
Different bindings may interpret “both” differently (intersection vs precedence vs union), and may or may not validate that the browsing context belongs to the user context.
## Fix Focus Areas
- docs/decisions/17685-network-handler-behavior.md[270-274]
- docs/decisions/17685-network-handler-behavior.md[382-383]
## Suggested fix
Add explicit normative rules covering:
- whether supplying both means intersection (BC within UC), precedence (one overrides), or union
- required validation when the browsing context is not part of the user context (error vs ignore one)
- behavior when the default scope cannot be resolved from the “current window” (e.g., no active window)
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit d87ed06 |
… match or expand them
| valid pattern errors. A binding may log a warning when a value looks like a | ||
| glob, to flag that Selenium forwards it rather than expanding it; that | ||
| detection is optional and left to the binding rather than specified here. |
There was a problem hiding this comment.
1. glob warning left optional 📘 Rule violation ⚙ Maintainability
The ADR makes glob-looking pattern warnings optional per binding, which enables user-visible divergence across language bindings. This conflicts with the cross-binding consistency requirement for shared behavior expectations.
Agent Prompt
## Issue description
The ADR states that logging a warning for glob-looking URL patterns is optional per binding, which invites inconsistent user-visible behavior across bindings.
## Issue Context
This ADR is meant to align cross-binding behavior for the network handler API; optional warnings undermine that alignment unless a clear follow-up plan is recorded.
## Fix Focus Areas
- docs/decisions/17685-network-handler-behavior.md[80-82]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit 7d08abd |
📄 The decision, its rationale, considered options, and consequences are in the record file this PR
adds (
docs/decisions/17685-network-handler-behavior.md);read it there. This body is context for the decision, not a restatement of it.
🔗 Related
under
driver.network) agreed at the Dev Summit; this record consolidates it, and the per-bindingimplementation history is tracked there.
driver.networkis the protocol-neutralsurface consistent with that boundary.
where @nvborisenko and I raised behavior concerns that were never resolved before meetings stopped —
this record settles them.
📝 Proposal notes
async/event API bucket; on acceptance the charter links back to it.
driver.networkaccessor, and add / remove / clear handlers for requests, responses, and authentication. The rest
of the record settles how those handlers behave.
settles. Whether to add non-blocking observation — and, if so, whether as a mode on these methods
or its own surface — is a separate ADR; the last TLC discussion leaned toward blocking everything
for now, and @nvborisenko and @diemol have argued observation is distinct enough to stand on its
own. Nothing here forecloses that: it arrives later as an opt-in, leaving the blocking default
intact.
illustration, this Ruby sketch — each handler run in turn, later-registered first, the event settled
by the first to act — satisfies them:
🗣 Discussion
Pending — not yet discussed.
📌 Tracking
Tracking issue: (linked on acceptance)