Skip to content

Commit d941520

Browse files
refactor: use caching attribute client (#76)
* refactor: use caching attribute client * chore: update snyk expiration * style: spotless
1 parent 2edb271 commit d941520

File tree

8 files changed

+104
-322
lines changed

8 files changed

+104
-322
lines changed

.snyk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ ignore:
55
SNYK-JAVA-IONETTY-1042268:
66
- '*':
77
reason: No replacement available
8-
expires: 2021-09-01T00:00:00.000Z
8+
expires: 2021-12-31T00:00:00.000Z
99
patch: {}
1010

hypertrace-core-graphql-attribute-store/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ dependencies {
1313
implementation("io.reactivex.rxjava3:rxjava")
1414
implementation("com.google.guava:guava")
1515

16-
implementation("org.hypertrace.core.attribute.service:attribute-service-api")
16+
implementation("org.hypertrace.core.attribute.service:caching-attribute-service-client")
1717
implementation("org.hypertrace.core.grpcutils:grpc-client-rx-utils")
1818
implementation(project(":hypertrace-core-graphql-grpc-utils"))
1919
implementation(project(":hypertrace-core-graphql-rx-utils"))

hypertrace-core-graphql-attribute-store/src/main/java/org/hypertrace/core/graphql/attributes/AttributeClient.java

Lines changed: 0 additions & 57 deletions
This file was deleted.

hypertrace-core-graphql-attribute-store/src/main/java/org/hypertrace/core/graphql/attributes/AttributeStore.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
package org.hypertrace.core.graphql.attributes;
22

33
import io.reactivex.rxjava3.core.Single;
4-
import java.util.Collection;
54
import java.util.List;
6-
import java.util.Map;
75
import org.hypertrace.core.graphql.context.GraphQlRequestContext;
86

97
public interface AttributeStore {
108
Single<List<AttributeModel>> getAll(GraphQlRequestContext context);
119

1210
Single<AttributeModel> get(GraphQlRequestContext context, String scope, String key);
1311

14-
Single<Map<String, AttributeModel>> get(
15-
GraphQlRequestContext context, String scope, Collection<String> keys);
16-
1712
Single<AttributeModel> getIdAttribute(GraphQlRequestContext context, String scope);
1813

1914
Single<AttributeModel> getForeignIdAttribute(

hypertrace-core-graphql-attribute-store/src/main/java/org/hypertrace/core/graphql/attributes/AttributeStoreModule.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import com.google.inject.AbstractModule;
44
import com.google.inject.Key;
55
import com.google.inject.multibindings.Multibinder;
6-
import io.grpc.CallCredentials;
76
import io.reactivex.rxjava3.core.Scheduler;
87
import org.hypertrace.core.graphql.rx.BoundedIoScheduler;
98
import org.hypertrace.core.graphql.spi.config.GraphQlServiceConfig;
@@ -19,7 +18,6 @@ protected void configure() {
1918
Multibinder.newSetBinder(binder(), IdMappingLoader.class);
2019
requireBinding(GraphQlServiceConfig.class);
2120
requireBinding(GrpcContextBuilder.class);
22-
requireBinding(CallCredentials.class);
2321
requireBinding(GrpcChannelRegistry.class);
2422
requireBinding(Key.get(Scheduler.class, BoundedIoScheduler.class));
2523
}

hypertrace-core-graphql-attribute-store/src/main/java/org/hypertrace/core/graphql/attributes/CachingAttributeStore.java

Lines changed: 48 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,74 @@
11
package org.hypertrace.core.graphql.attributes;
22

3-
import com.google.common.cache.CacheBuilder;
4-
import com.google.common.cache.CacheLoader;
5-
import com.google.common.cache.LoadingCache;
6-
import com.google.common.collect.ImmutableTable;
7-
import com.google.common.collect.Table;
8-
import io.reactivex.rxjava3.core.Observable;
93
import io.reactivex.rxjava3.core.Single;
10-
import java.util.Collection;
4+
import java.time.Duration;
115
import java.util.List;
12-
import java.util.Map;
136
import java.util.NoSuchElementException;
14-
import java.util.Optional;
15-
import java.util.concurrent.TimeUnit;
16-
import java.util.function.Function;
17-
import java.util.stream.Collectors;
187
import javax.inject.Inject;
198
import javax.inject.Singleton;
20-
import org.hypertrace.core.graphql.context.ContextualCachingKey;
9+
import org.hypertrace.core.attribute.service.cachingclient.CachingAttributeClient;
2110
import org.hypertrace.core.graphql.context.GraphQlRequestContext;
11+
import org.hypertrace.core.graphql.spi.config.GraphQlServiceConfig;
12+
import org.hypertrace.core.graphql.utils.grpc.GrpcChannelRegistry;
13+
import org.hypertrace.core.graphql.utils.grpc.GrpcContextBuilder;
14+
import org.hypertrace.core.grpcutils.client.rx.GrpcRxExecutionContext;
2215

2316
@Singleton
2417
class CachingAttributeStore implements AttributeStore {
2518

26-
private final AttributeClient attributeClient;
19+
private final CachingAttributeClient cachingAttributeClient;
2720
private final IdLookup idLookup;
21+
private final GrpcContextBuilder grpcContextBuilder;
22+
private final AttributeModelTranslator translator;
2823

2924
@Inject
30-
CachingAttributeStore(AttributeClient attributeClient, IdLookup idLookup) {
31-
this.attributeClient = attributeClient;
32-
this.idLookup = idLookup;
25+
CachingAttributeStore(
26+
IdLookup idLookup,
27+
GrpcContextBuilder grpcContextBuilder,
28+
AttributeModelTranslator translator,
29+
GrpcChannelRegistry channelRegistry,
30+
GraphQlServiceConfig serviceConfig) {
31+
this(
32+
idLookup,
33+
grpcContextBuilder,
34+
translator,
35+
CachingAttributeClient.builder(
36+
channelRegistry.forAddress(
37+
serviceConfig.getAttributeServiceHost(),
38+
serviceConfig.getAttributeServicePort()))
39+
.withCacheExpiration(Duration.ofMinutes(5))
40+
.withMaximumCacheContexts(1000)
41+
.build());
3342
}
3443

35-
private final LoadingCache<ContextualCachingKey, Single<Table<String, String, AttributeModel>>>
36-
cache =
37-
CacheBuilder.newBuilder()
38-
.maximumSize(1000)
39-
.expireAfterWrite(15, TimeUnit.MINUTES)
40-
.build(CacheLoader.from(this::loadTable));
41-
42-
@Override
43-
public Single<List<AttributeModel>> getAll(GraphQlRequestContext context) {
44-
return this.getOrInvalidate(context).map(table -> List.copyOf(table.values()));
44+
CachingAttributeStore(
45+
IdLookup idLookup,
46+
GrpcContextBuilder grpcContextBuilder,
47+
AttributeModelTranslator translator,
48+
CachingAttributeClient cachingAttributeClient) {
49+
this.idLookup = idLookup;
50+
this.grpcContextBuilder = grpcContextBuilder;
51+
this.translator = translator;
52+
this.cachingAttributeClient = cachingAttributeClient;
4553
}
4654

4755
@Override
48-
public Single<AttributeModel> get(GraphQlRequestContext context, String scope, String key) {
49-
return this.getOrInvalidate(context)
50-
.mapOptional(table -> Optional.ofNullable(table.get(scope, key)))
51-
.switchIfEmpty(Single.error(this.buildErrorForMissingAttribute(scope, key)));
56+
public Single<List<AttributeModel>> getAll(GraphQlRequestContext requestContext) {
57+
return GrpcRxExecutionContext.forContext(this.grpcContextBuilder.build(requestContext))
58+
.wrapSingle(this.cachingAttributeClient::getAll)
59+
.flattenAsObservable(list -> list)
60+
.mapOptional(this.translator::translate)
61+
.toList();
5262
}
5363

5464
@Override
55-
public Single<Map<String, AttributeModel>> get(
56-
GraphQlRequestContext context, String scope, Collection<String> keys) {
57-
return this.getOrInvalidate(context)
58-
.flatMap(table -> this.getValuesOrError(scope, table.row(scope), keys));
65+
public Single<AttributeModel> get(
66+
GraphQlRequestContext requestContext, String scope, String key) {
67+
return GrpcRxExecutionContext.forContext(this.grpcContextBuilder.build(requestContext))
68+
.wrapSingle(() -> this.cachingAttributeClient.get(scope, key))
69+
.toMaybe()
70+
.mapOptional(this.translator::translate)
71+
.switchIfEmpty(Single.error(this.buildErrorForMissingAttribute(scope, key)));
5972
}
6073

6174
@Override
@@ -70,28 +83,6 @@ public Single<AttributeModel> getForeignIdAttribute(
7083
.flatMap(key -> this.get(context, scope, key));
7184
}
7285

73-
private Single<Table<String, String, AttributeModel>> loadTable(ContextualCachingKey cachingKey) {
74-
return this.attributeClient
75-
.queryAll(cachingKey.getContext())
76-
.toList()
77-
.map(this::buildTable)
78-
.cache();
79-
}
80-
81-
private Table<String, String, AttributeModel> buildTable(List<AttributeModel> attributes) {
82-
return attributes.stream()
83-
.collect(
84-
ImmutableTable.toImmutableTable(
85-
AttributeModel::scope, AttributeModel::key, Function.identity()));
86-
}
87-
88-
private Single<Table<String, String, AttributeModel>> getOrInvalidate(
89-
GraphQlRequestContext context) {
90-
return this.cache
91-
.getUnchecked(context.getCachingKey())
92-
.doOnError(x -> this.cache.invalidate(context.getCachingKey()));
93-
}
94-
9586
private Single<String> getForeignIdKey(
9687
GraphQlRequestContext context, String scope, String foreignScope) {
9788
return this.idLookup
@@ -106,19 +97,6 @@ private Single<String> getIdKey(GraphQlRequestContext context, String scope) {
10697
.switchIfEmpty(Single.error(this.buildErrorForMissingIdMapping(scope)));
10798
}
10899

109-
private Single<Map<String, AttributeModel>> getValuesOrError(
110-
String scope,
111-
Map<String, AttributeModel> definedAttributes,
112-
Collection<String> requestedAttributeKeys) {
113-
return Observable.fromIterable(requestedAttributeKeys)
114-
.flatMap(
115-
key ->
116-
definedAttributes.containsKey(key)
117-
? Observable.just(definedAttributes.get(key))
118-
: Observable.error(this.buildErrorForMissingAttribute(scope, key)))
119-
.collect(Collectors.toUnmodifiableMap(AttributeModel::key, Function.identity()));
120-
}
121-
122100
private NoSuchElementException buildErrorForMissingAttribute(String scope, String key) {
123101
return new NoSuchElementException(
124102
String.format("No attribute available for scope '%s' and key '%s'", scope, key));

0 commit comments

Comments
 (0)