Skip to content

Commit 90faf43

Browse files
Module Execution Host Config Check (#3566)
1 parent 7b3fd70 commit 90faf43

File tree

12 files changed

+565
-126
lines changed

12 files changed

+565
-126
lines changed

docs/application-settings.md

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ Keep in mind following restrictions:
101101
- `cookie-sync.pri` - a list of prioritized bidder codes
102102
- `cookie-sync.coop-sync.default` - if the "coopSync" value isn't specified in the `/cookie_sync` request, use this
103103
- `hooks` - configuration for Prebid Server Modules. For further details, see: https://docs.prebid.org/prebid-server/pbs-modules/index.html#2-define-an-execution-plan
104+
- `hooks.admin.module-execution` - a key-value map, where a key is a module name and a value is a boolean, that defines whether modules hooks should/should not be always executed; if the module is not specified it is executed by default when it's present in the execution plan
104105
- `settings.geo-lookup` - enables geo lookup for account if true. Defaults to false.
105106

106107
Here are the definitions of the "purposes" that can be defined in the GDPR setting configurations:

docs/config-app.md

+3
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,9 @@ contain 'WHERE last_updated > ?' for MySQL and 'WHERE last_updated > $1' for Pos
370370
For targeting available next options:
371371
- `settings.targeting.truncate-attr-chars` - set the max length for names of targeting keywords (0 means no truncation).
372372

373+
For modules:
374+
- `settings.modules.require-config-to-invoke` - when enabled it requires a runtime config to exist for a module.
375+
373376
## Host Cookie
374377
- `host-cookie.optout-cookie.name` - set the cookie name for optout checking.
375378
- `host-cookie.optout-cookie.value` - set the cookie value for optout checking.

src/main/java/org/prebid/server/hooks/execution/GroupExecutor.java

+11-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.prebid.server.hooks.execution;
22

3-
import com.fasterxml.jackson.databind.node.ObjectNode;
43
import io.vertx.core.AsyncResult;
54
import io.vertx.core.Future;
65
import io.vertx.core.Promise;
@@ -9,16 +8,13 @@
98
import org.prebid.server.hooks.execution.model.HookExecutionContext;
109
import org.prebid.server.hooks.execution.model.HookId;
1110
import org.prebid.server.hooks.v1.Hook;
12-
import org.prebid.server.hooks.v1.InvocationAction;
1311
import org.prebid.server.hooks.v1.InvocationContext;
1412
import org.prebid.server.hooks.v1.InvocationResult;
15-
import org.prebid.server.hooks.v1.InvocationResultImpl;
16-
import org.prebid.server.hooks.v1.InvocationStatus;
17-
import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
1813
import org.prebid.server.log.ConditionalLogger;
1914
import org.prebid.server.log.LoggerFactory;
2015

2116
import java.time.Clock;
17+
import java.util.Map;
2218
import java.util.concurrent.TimeoutException;
2319
import java.util.function.Function;
2420
import java.util.function.Supplier;
@@ -30,7 +26,7 @@ class GroupExecutor<PAYLOAD, CONTEXT extends InvocationContext> {
3026

3127
private final Vertx vertx;
3228
private final Clock clock;
33-
private final boolean isConfigToInvokeRequired;
29+
private final Map<String, Boolean> modulesExecution;
3430

3531
private ExecutionGroup group;
3632
private PAYLOAD initialPayload;
@@ -39,18 +35,19 @@ class GroupExecutor<PAYLOAD, CONTEXT extends InvocationContext> {
3935
private HookExecutionContext hookExecutionContext;
4036
private boolean rejectAllowed;
4137

42-
private GroupExecutor(Vertx vertx, Clock clock, boolean isConfigToInvokeRequired) {
38+
private GroupExecutor(Vertx vertx, Clock clock, Map<String, Boolean> modulesExecution) {
39+
4340
this.vertx = vertx;
4441
this.clock = clock;
45-
this.isConfigToInvokeRequired = isConfigToInvokeRequired;
42+
this.modulesExecution = modulesExecution;
4643
}
4744

4845
public static <PAYLOAD, CONTEXT extends InvocationContext> GroupExecutor<PAYLOAD, CONTEXT> create(
4946
Vertx vertx,
5047
Clock clock,
51-
boolean isConfigToInvokeRequired) {
48+
Map<String, Boolean> modulesExecution) {
5249

53-
return new GroupExecutor<>(vertx, clock, isConfigToInvokeRequired);
50+
return new GroupExecutor<>(vertx, clock, modulesExecution);
5451
}
5552

5653
public GroupExecutor<PAYLOAD, CONTEXT> withGroup(ExecutionGroup group) {
@@ -90,6 +87,10 @@ public Future<GroupResult<PAYLOAD>> execute() {
9087
Future<GroupResult<PAYLOAD>> groupFuture = Future.succeededFuture(initialGroupResult);
9188

9289
for (final HookId hookId : group.getHookSequence()) {
90+
if (!modulesExecution.getOrDefault(hookId.getModuleCode(), true)) {
91+
continue;
92+
}
93+
9394
final Hook<PAYLOAD, CONTEXT> hook = hookProvider.apply(hookId);
9495

9596
final long startTime = clock.millis();
@@ -116,17 +117,6 @@ private Future<InvocationResult<PAYLOAD>> executeHook(
116117
}
117118

118119
final CONTEXT invocationContext = invocationContextProvider.apply(timeout, hookId, moduleContextFor(hookId));
119-
120-
if (isConfigToInvokeRequired && invocationContext instanceof AuctionInvocationContext) {
121-
final ObjectNode accountConfig = ((AuctionInvocationContext) invocationContext).accountConfig();
122-
if (accountConfig == null || accountConfig.isNull()) {
123-
return Future.succeededFuture(InvocationResultImpl.<PAYLOAD>builder()
124-
.status(InvocationStatus.success)
125-
.action(InvocationAction.no_invocation)
126-
.build());
127-
}
128-
}
129-
130120
return executeWithTimeout(() -> hook.call(groupResult.payload(), invocationContext), timeout);
131121
}
132122

src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java

+28-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.iab.openrtb.response.BidResponse;
66
import io.vertx.core.Future;
77
import io.vertx.core.Vertx;
8+
import org.apache.commons.collections4.map.DefaultedMap;
89
import org.apache.commons.lang3.ObjectUtils;
910
import org.apache.commons.lang3.StringUtils;
1011
import org.prebid.server.auction.model.AuctionContext;
@@ -46,14 +47,17 @@
4647
import org.prebid.server.model.CaseInsensitiveMultiMap;
4748
import org.prebid.server.model.Endpoint;
4849
import org.prebid.server.settings.model.Account;
50+
import org.prebid.server.settings.model.HooksAdminConfig;
4951
import org.prebid.server.settings.model.AccountHooksConfiguration;
5052

5153
import java.time.Clock;
5254
import java.util.Collection;
5355
import java.util.Collections;
56+
import java.util.HashMap;
5457
import java.util.List;
5558
import java.util.Map;
5659
import java.util.Objects;
60+
import java.util.Optional;
5761
import java.util.stream.Stream;
5862

5963
public class HookStageExecutor {
@@ -123,6 +127,7 @@ public Future<HookStageExecutionResult<EntrypointPayload>> executeEntrypointStag
123127
.withExecutionPlan(planForEntrypointStage(endpoint))
124128
.withInitialPayload(EntrypointPayloadImpl.of(queryParams, headers, body))
125129
.withInvocationContextProvider(invocationContextProvider(endpoint))
130+
.withModulesExecution(Collections.emptyMap())
126131
.withRejectAllowed(true)
127132
.execute();
128133
}
@@ -259,7 +264,7 @@ private <PAYLOAD, CONTEXT extends InvocationContext> StageExecutor<PAYLOAD, CONT
259264
String entity,
260265
HookExecutionContext context) {
261266

262-
return StageExecutor.<PAYLOAD, CONTEXT>create(hookCatalog, vertx, clock, isConfigToInvokeRequired)
267+
return StageExecutor.<PAYLOAD, CONTEXT>create(hookCatalog, vertx, clock)
263268
.withStage(stage)
264269
.withEntity(entity)
265270
.withHookExecutionContext(context);
@@ -273,9 +278,30 @@ private <PAYLOAD, CONTEXT extends InvocationContext> StageExecutor<PAYLOAD, CONT
273278
Endpoint endpoint) {
274279

275280
return stageExecutor(stage, entity, context)
281+
.withModulesExecution(modulesExecutionForAccount(account))
276282
.withExecutionPlan(planForStage(account, endpoint, stage.stage()));
277283
}
278284

285+
private Map<String, Boolean> modulesExecutionForAccount(Account account) {
286+
final Map<String, Boolean> accountModulesExecution = Optional.ofNullable(account.getHooks())
287+
.map(AccountHooksConfiguration::getAdmin)
288+
.map(HooksAdminConfig::getModuleExecution)
289+
.orElse(Collections.emptyMap());
290+
291+
final Map<String, Boolean> resultModulesExecution = new HashMap<>(accountModulesExecution);
292+
293+
if (isConfigToInvokeRequired) {
294+
Optional.ofNullable(account.getHooks())
295+
.map(AccountHooksConfiguration::getModules)
296+
.map(Map::keySet)
297+
.stream()
298+
.flatMap(Collection::stream)
299+
.forEach(module -> resultModulesExecution.computeIfAbsent(module, key -> true));
300+
}
301+
302+
return DefaultedMap.defaultedMap(resultModulesExecution, !isConfigToInvokeRequired);
303+
}
304+
279305
private static ExecutionPlan parseAndValidateExecutionPlan(
280306
String executionPlan,
281307
JacksonMapper mapper,
@@ -402,8 +428,7 @@ private InvocationContextProvider<BidderInvocationContext> bidderInvocationConte
402428
String bidder) {
403429

404430
return (timeout, hookId, moduleContext) -> BidderInvocationContextImpl.of(
405-
auctionInvocationContext(endpoint, timeout, auctionContext, hookId, moduleContext),
406-
bidder);
431+
auctionInvocationContext(endpoint, timeout, auctionContext, hookId, moduleContext), bidder);
407432
}
408433

409434
private Timeout createTimeout(Long timeout) {

src/main/java/org/prebid/server/hooks/execution/StageExecutor.java

+11-7
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212

1313
import java.time.Clock;
1414
import java.util.ArrayList;
15+
import java.util.Map;
1516

1617
class StageExecutor<PAYLOAD, CONTEXT extends InvocationContext> {
1718

1819
private final HookCatalog hookCatalog;
1920
private final Vertx vertx;
2021
private final Clock clock;
21-
private final boolean isConfigToInvokeRequired;
2222

2323
private StageWithHookType<? extends Hook<PAYLOAD, CONTEXT>> stage;
2424
private String entity;
@@ -27,21 +27,20 @@ class StageExecutor<PAYLOAD, CONTEXT extends InvocationContext> {
2727
private InvocationContextProvider<CONTEXT> invocationContextProvider;
2828
private HookExecutionContext hookExecutionContext;
2929
private boolean rejectAllowed;
30+
private Map<String, Boolean> modulesExecution;
3031

31-
private StageExecutor(HookCatalog hookCatalog, Vertx vertx, Clock clock, boolean isConfigToInvokeRequired) {
32+
private StageExecutor(HookCatalog hookCatalog, Vertx vertx, Clock clock) {
3233
this.hookCatalog = hookCatalog;
3334
this.vertx = vertx;
3435
this.clock = clock;
35-
this.isConfigToInvokeRequired = isConfigToInvokeRequired;
3636
}
3737

3838
public static <PAYLOAD, CONTEXT extends InvocationContext> StageExecutor<PAYLOAD, CONTEXT> create(
3939
HookCatalog hookCatalog,
4040
Vertx vertx,
41-
Clock clock,
42-
boolean isConfigToInvokeRequired) {
41+
Clock clock) {
4342

44-
return new StageExecutor<>(hookCatalog, vertx, clock, isConfigToInvokeRequired);
43+
return new StageExecutor<>(hookCatalog, vertx, clock);
4544
}
4645

4746
public StageExecutor<PAYLOAD, CONTEXT> withStage(StageWithHookType<? extends Hook<PAYLOAD, CONTEXT>> stage) {
@@ -81,6 +80,11 @@ public StageExecutor<PAYLOAD, CONTEXT> withRejectAllowed(boolean rejectAllowed)
8180
return this;
8281
}
8382

83+
public StageExecutor<PAYLOAD, CONTEXT> withModulesExecution(Map<String, Boolean> modulesExecution) {
84+
this.modulesExecution = modulesExecution;
85+
return this;
86+
}
87+
8488
public Future<HookStageExecutionResult<PAYLOAD>> execute() {
8589
Future<StageResult<PAYLOAD>> stageFuture = Future.succeededFuture(StageResult.of(initialPayload, entity));
8690

@@ -97,7 +101,7 @@ public Future<HookStageExecutionResult<PAYLOAD>> execute() {
97101
}
98102

99103
private Future<GroupResult<PAYLOAD>> executeGroup(ExecutionGroup group, PAYLOAD initialPayload) {
100-
return GroupExecutor.<PAYLOAD, CONTEXT>create(vertx, clock, isConfigToInvokeRequired)
104+
return GroupExecutor.<PAYLOAD, CONTEXT>create(vertx, clock, modulesExecution)
101105
.withGroup(group)
102106
.withInitialPayload(initialPayload)
103107
.withHookProvider(

src/main/java/org/prebid/server/settings/model/AccountHooksConfiguration.java

+2
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ public class AccountHooksConfiguration {
1414
ExecutionPlan executionPlan;
1515

1616
Map<String, ObjectNode> modules;
17+
18+
HooksAdminConfig admin;
1719
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.prebid.server.settings.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonAlias;
4+
import lombok.Builder;
5+
import lombok.Value;
6+
7+
import java.util.Map;
8+
9+
@Builder
10+
@Value
11+
public class HooksAdminConfig {
12+
13+
@JsonAlias("module-execution")
14+
Map<String, Boolean> moduleExecution;
15+
16+
}

src/test/groovy/org/prebid/server/functional/model/config/AccountHooksConfiguration.groovy

+1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ class AccountHooksConfiguration {
1313
@JsonProperty("execution_plan")
1414
ExecutionPlan executionPlanSnakeCase
1515
PbsModulesConfig modules
16+
AdminConfig admin
1617
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.prebid.server.functional.model.config
2+
3+
import com.fasterxml.jackson.databind.PropertyNamingStrategies
4+
import com.fasterxml.jackson.databind.annotation.JsonNaming
5+
import groovy.transform.ToString
6+
import org.prebid.server.functional.model.ModuleName
7+
8+
@ToString(includeNames = true, ignoreNulls = true)
9+
@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy)
10+
class AdminConfig {
11+
12+
Map<ModuleName, Boolean> moduleExecution
13+
}

src/test/groovy/org/prebid/server/functional/model/response/auction/TraceOutcome.groovy

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ package org.prebid.server.functional.model.response.auction
33
import com.fasterxml.jackson.databind.PropertyNamingStrategies
44
import com.fasterxml.jackson.databind.annotation.JsonNaming
55
import groovy.transform.ToString
6-
import org.prebid.server.functional.model.config.Stage
76

87
@ToString(includeNames = true, ignoreNulls = true)
98
@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy)
109
class TraceOutcome {
1110

12-
Stage entity
11+
String entity
1312
Long executionTimeMillis
1413
List<TraceGroup> groups
1514
}

0 commit comments

Comments
 (0)