Skip to content

Commit 80f7c88

Browse files
committed
Allow clients to send stereotypes to help determine what to get from the new session queue
This is the first step in preventing the distributor from needing to maintain a list of request ids, which can easily get out of alignment with reality, and can contain stale entries if requests time out of the queue.
1 parent 71cc53b commit 80f7c88

22 files changed

+261
-14
lines changed

java/server/src/org/openqa/selenium/grid/commands/Hub.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.openqa.selenium.grid.distributor.Distributor;
2929
import org.openqa.selenium.grid.distributor.config.DistributorOptions;
3030
import org.openqa.selenium.grid.distributor.local.LocalDistributor;
31-
import org.openqa.selenium.grid.distributor.selector.DefaultSlotSelector;
3231
import org.openqa.selenium.grid.graphql.GraphqlHandler;
3332
import org.openqa.selenium.grid.log.LoggingOptions;
3433
import org.openqa.selenium.grid.router.ProxyCdpIntoGrid;
@@ -141,16 +140,17 @@ protected Handlers createHandlers(Config config) {
141140
handler,
142141
networkOptions.getHttpClientFactory(tracer));
143142

143+
DistributorOptions distributorOptions = new DistributorOptions(config);
144144
SessionRequestOptions sessionRequestOptions = new SessionRequestOptions(config);
145145
NewSessionQueue queue = new LocalNewSessionQueue(
146146
tracer,
147-
bus,
147+
bus,
148+
distributorOptions.getSlotMatcher(),
148149
sessionRequestOptions.getSessionRequestRetryInterval(),
149150
sessionRequestOptions.getSessionRequestTimeout(),
150151
secret);
151152
handler.addHandler(queue);
152153

153-
DistributorOptions distributorOptions = new DistributorOptions(config);
154154
Distributor distributor = new LocalDistributor(
155155
tracer,
156156
bus,

java/server/src/org/openqa/selenium/grid/commands/Standalone.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,17 @@ protected Handlers createHandlers(Config config) {
138138
SessionMap sessions = new LocalSessionMap(tracer, bus);
139139
combinedHandler.addHandler(sessions);
140140

141+
DistributorOptions distributorOptions = new DistributorOptions(config);
141142
SessionRequestOptions sessionRequestOptions = new SessionRequestOptions(config);
142143
NewSessionQueue queue = new LocalNewSessionQueue(
143144
tracer,
144145
bus,
146+
distributorOptions.getSlotMatcher(),
145147
sessionRequestOptions.getSessionRequestRetryInterval(),
146148
sessionRequestOptions.getSessionRequestTimeout(),
147149
registrationSecret);
148150
combinedHandler.addHandler(queue);
149151

150-
DistributorOptions distributorOptions = new DistributorOptions(config);
151152
Distributor distributor = new LocalDistributor(
152153
tracer,
153154
bus,

java/server/src/org/openqa/selenium/grid/data/SessionRequest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
import java.util.HashSet;
3434
import java.util.LinkedHashSet;
3535
import java.util.Map;
36+
import java.util.Objects;
3637
import java.util.Set;
38+
import java.util.StringJoiner;
3739
import java.util.TreeMap;
3840
import java.util.stream.Collectors;
3941

@@ -99,6 +101,34 @@ public Instant getEnqueued() {
99101
return enqueued;
100102
}
101103

104+
@Override
105+
public String toString() {
106+
return new StringJoiner(", ", SessionRequest.class.getSimpleName() + "[", "]")
107+
.add("requestId=" + requestId)
108+
.add("desiredCapabilities=" + desiredCapabilities)
109+
.add("downstreamDialects=" + downstreamDialects)
110+
.add("metadata=" + metadata)
111+
.toString();
112+
}
113+
114+
@Override
115+
public boolean equals(Object o) {
116+
if (!(o instanceof SessionRequest)) {
117+
return false;
118+
}
119+
SessionRequest that = (SessionRequest) o;
120+
121+
return this.requestId.equals(that.requestId) &&
122+
this.desiredCapabilities.equals(that.desiredCapabilities) &&
123+
this.downstreamDialects.equals(that.downstreamDialects) &&
124+
this.metadata.equals(that.metadata);
125+
}
126+
127+
@Override
128+
public int hashCode() {
129+
return Objects.hash(requestId, enqueued, desiredCapabilities, downstreamDialects, metadata);
130+
}
131+
102132
private Map<String, Object> toJson() {
103133
Map<String, Object> toReturn = new HashMap<>();
104134
toReturn.put("requestId", requestId);

java/server/src/org/openqa/selenium/grid/data/SlotMatcher.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
import org.openqa.selenium.Capabilities;
2121

22-
/** Used to determine how a {@link Slot} can match its
22+
/**
23+
* Used to determine how a {@link Slot} can match its
2324
* stereotype to the capabilities sent in a particular
2425
* New Session request.
2526
*/

java/server/src/org/openqa/selenium/grid/distributor/config/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ java_library(
1010
deps = [
1111
"//java:auto-service",
1212
"//java/server/src/org/openqa/selenium/grid/config",
13+
"//java/server/src/org/openqa/selenium/grid/data",
1314
"//java/server/src/org/openqa/selenium/grid/distributor",
1415
"//java/server/src/org/openqa/selenium/grid/distributor/selector",
1516
artifact("com.beust:jcommander"),

java/server/src/org/openqa/selenium/grid/distributor/config/DistributorFlags.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static org.openqa.selenium.grid.config.StandardGridRoles.DISTRIBUTOR_ROLE;
2222
import static org.openqa.selenium.grid.distributor.config.DistributorOptions.DEFAULT_DISTRIBUTOR_IMPLEMENTATION;
2323
import static org.openqa.selenium.grid.distributor.config.DistributorOptions.DEFAULT_HEALTHCHECK_INTERVAL;
24+
import static org.openqa.selenium.grid.distributor.config.DistributorOptions.DEFAULT_SLOT_MATCHER;
2425
import static org.openqa.selenium.grid.distributor.config.DistributorOptions.DEFAULT_SLOT_SELECTOR_IMPLEMENTATION;
2526
import static org.openqa.selenium.grid.distributor.config.DistributorOptions.DISTRIBUTOR_SECTION;
2627

@@ -65,7 +66,15 @@ public class DistributorFlags implements HasRoles {
6566
example = DEFAULT_DISTRIBUTOR_IMPLEMENTATION)
6667
private String implementation = DEFAULT_DISTRIBUTOR_IMPLEMENTATION;
6768

68-
@Parameter(names = {"--slot-selector"}, description = "Full classname of non-default slot selector implementation")
69+
@Parameter(
70+
names = {"--slot-matcher"},
71+
description = "Full classname of non-default slot matcher to use. This is used to determine whether a Node can support a particular session.")
72+
@ConfigValue(section = DISTRIBUTOR_SECTION, name = "slot-matcher", example = DEFAULT_SLOT_MATCHER)
73+
private String slotMatcher = DEFAULT_SLOT_MATCHER;
74+
75+
@Parameter(
76+
names = {"--slot-selector"},
77+
description = "Full classname of non-default slot selector. This is used to select a slot in a Node once the Node has been matched.")
6978
@ConfigValue(section = DISTRIBUTOR_SECTION, name = "slot-selector", example = DEFAULT_SLOT_SELECTOR_IMPLEMENTATION)
7079
private String slotSelector = DEFAULT_SLOT_SELECTOR_IMPLEMENTATION;
7180

java/server/src/org/openqa/selenium/grid/distributor/config/DistributorOptions.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.openqa.selenium.grid.config.Config;
2121
import org.openqa.selenium.grid.config.ConfigException;
22+
import org.openqa.selenium.grid.data.SlotMatcher;
2223
import org.openqa.selenium.grid.distributor.Distributor;
2324
import org.openqa.selenium.grid.distributor.selector.SlotSelector;
2425

@@ -32,6 +33,7 @@ public class DistributorOptions {
3233
static final String DISTRIBUTOR_SECTION = "distributor";
3334
static final String DEFAULT_DISTRIBUTOR_IMPLEMENTATION =
3435
"org.openqa.selenium.grid.distributor.local.LocalDistributor";
36+
static final String DEFAULT_SLOT_MATCHER = "org.openqa.selenium.grid.data.DefaultSlotMatcher";
3537
static final String DEFAULT_SLOT_SELECTOR_IMPLEMENTATION =
3638
"org.openqa.selenium.grid.distributor.selector.DefaultSlotSelector";
3739

@@ -96,6 +98,14 @@ public Distributor getDistributor() {
9698
DEFAULT_DISTRIBUTOR_IMPLEMENTATION);
9799
}
98100

101+
public SlotMatcher getSlotMatcher() {
102+
return config.getClass(
103+
DISTRIBUTOR_SECTION,
104+
"slot-matcher",
105+
SlotMatcher.class,
106+
DEFAULT_SLOT_MATCHER);
107+
}
108+
99109
public SlotSelector getSlotSelector() {
100110
return config.getClass(
101111
DISTRIBUTOR_SECTION,
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.sessionqueue;
19+
20+
import org.openqa.selenium.Capabilities;
21+
import org.openqa.selenium.grid.data.SessionRequest;
22+
import org.openqa.selenium.internal.Require;
23+
import org.openqa.selenium.json.TypeToken;
24+
import org.openqa.selenium.remote.http.Contents;
25+
import org.openqa.selenium.remote.http.HttpHandler;
26+
import org.openqa.selenium.remote.http.HttpRequest;
27+
import org.openqa.selenium.remote.http.HttpResponse;
28+
29+
import java.io.UncheckedIOException;
30+
import java.lang.reflect.Type;
31+
import java.util.Optional;
32+
import java.util.Set;
33+
34+
import static java.util.Collections.singletonMap;
35+
36+
class GetNextMatchingRequest implements HttpHandler {
37+
private static final Type SET_OF_CAPABILITIES = new TypeToken<Set<Capabilities>>() {}.getType();
38+
39+
private final NewSessionQueue queue;
40+
41+
public GetNextMatchingRequest(NewSessionQueue queue) {
42+
this.queue = Require.nonNull("New session queue", queue);
43+
}
44+
45+
@Override
46+
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
47+
Set<Capabilities> stereotypes = Contents.fromJson(req, SET_OF_CAPABILITIES);
48+
49+
Optional<SessionRequest> maybeRequest = queue.getNextAvailable(stereotypes);
50+
51+
return new HttpResponse().setContent(Contents.asJson(singletonMap("value", maybeRequest.orElse(null))));
52+
}
53+
}

java/server/src/org/openqa/selenium/grid/sessionqueue/NewSessionQueue.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,12 @@ protected NewSessionQueue(Tracer tracer, Secret registrationSecret) {
9090
post("/se/grid/newsessionqueue/session/{requestId}/success")
9191
.to(params -> new SessionCreated(tracer, this, requestIdFrom(params)))
9292
.with(requiresSecret),
93-
get("/se/grid/newsessionqueue/session/{requestId}")
93+
post("/se/grid/newsessionqueue/session/{requestId}")
9494
.to(params -> new RemoveFromSessionQueue(tracer, this, requestIdFrom(params)))
9595
.with(requiresSecret),
96+
post("/se/grid/newsessionqueue/session/next")
97+
.to(() -> new GetNextMatchingRequest(this))
98+
.with(requiresSecret),
9699
get("/se/grid/newsessionqueue/queue")
97100
.to(() -> new GetSessionQueue(tracer, this)),
98101
delete("/se/grid/newsessionqueue/queue")
@@ -110,6 +113,8 @@ private RequestId requestIdFrom(Map<String, String> params) {
110113

111114
public abstract Optional<SessionRequest> remove(RequestId reqId);
112115

116+
public abstract Optional<SessionRequest> getNextAvailable(Set<Capabilities> stereotypes);
117+
113118
public abstract void complete(RequestId reqId, Either<SessionNotCreatedException, CreateSessionResponse> result);
114119

115120
public abstract int clearQueue();

java/server/src/org/openqa/selenium/grid/sessionqueue/local/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ java_library(
1515
"//java/server/src/org/openqa/selenium/events",
1616
"//java/server/src/org/openqa/selenium/grid/config",
1717
"//java/server/src/org/openqa/selenium/grid/data",
18+
"//java/server/src/org/openqa/selenium/grid/distributor/config",
1819
"//java/server/src/org/openqa/selenium/grid/jmx",
1920
"//java/server/src/org/openqa/selenium/grid/log",
2021
"//java/server/src/org/openqa/selenium/grid/security",

0 commit comments

Comments
 (0)