-
Notifications
You must be signed in to change notification settings - Fork 612
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Backport stable/8.4] Fix identity-sdk concurrency issue (#24269)
# Description Backport of #24196 to `stable/8.4`. relates to #23853 original author: @koevskinikola
- Loading branch information
Showing
13 changed files
with
828 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
gateway/src/main/java/io/camunda/zeebe/gateway/cmd/ConcurrentRequestException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under | ||
* one or more contributor license agreements. See the NOTICE file distributed | ||
* with this work for additional information regarding copyright ownership. | ||
* Licensed under the Zeebe Community License 1.1. You may not use this file | ||
* except in compliance with the Zeebe Community License 1.1. | ||
*/ | ||
package io.camunda.zeebe.gateway.cmd; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
public class ConcurrentRequestException extends ClientException { | ||
|
||
private static final String MESSAGE_FORMAT = | ||
"Expected to fetch tenants from Identity within %d%s, but there are too many concurrent requests; either increase the tenant request capacity, or scale Identity to complete requests faster."; | ||
|
||
public ConcurrentRequestException(final long timeout, final TimeUnit timeoutUnit) { | ||
super(String.format(MESSAGE_FORMAT, timeout, timeoutUnit)); | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
gateway/src/main/java/io/camunda/zeebe/gateway/impl/configuration/ExperimentalCfg.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under | ||
* one or more contributor license agreements. See the NOTICE file distributed | ||
* with this work for additional information regarding copyright ownership. | ||
* Licensed under the Zeebe Community License 1.1. You may not use this file | ||
* except in compliance with the Zeebe Community License 1.1. | ||
*/ | ||
package io.camunda.zeebe.gateway.impl.configuration; | ||
|
||
import java.util.Objects; | ||
|
||
/** | ||
* Be aware that all configuration which are part of this class are experimental, which means they | ||
* are subject to change and to drop. It might be that also some of them are actually dangerous so | ||
* be aware when you change one of these! | ||
*/ | ||
public class ExperimentalCfg { | ||
|
||
private IdentityServiceCfg identityRequest = new IdentityServiceCfg(); | ||
|
||
public IdentityServiceCfg getIdentityRequest() { | ||
return identityRequest; | ||
} | ||
|
||
public void setIdentityRequest(final IdentityServiceCfg identityRequest) { | ||
this.identityRequest = identityRequest; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(identityRequest); | ||
} | ||
|
||
@Override | ||
public boolean equals(final Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
final ExperimentalCfg that = (ExperimentalCfg) o; | ||
return Objects.equals(identityRequest, that.identityRequest); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "ExperimentalCfg{" + "identityRequest=" + identityRequest + '}'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
gateway/src/main/java/io/camunda/zeebe/gateway/impl/configuration/IdentityServiceCfg.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under | ||
* one or more contributor license agreements. See the NOTICE file distributed | ||
* with this work for additional information regarding copyright ownership. | ||
* Licensed under the Zeebe Community License 1.1. You may not use this file | ||
* except in compliance with the Zeebe Community License 1.1. | ||
*/ | ||
package io.camunda.zeebe.gateway.impl.configuration; | ||
|
||
import java.util.Objects; | ||
|
||
public class IdentityServiceCfg { | ||
|
||
private boolean enabled = false; | ||
private long tenantCacheTtl = 5000; | ||
private long tenantCacheSize = 200; | ||
private int tenantRequestCapacity = 300; | ||
private long tenantRequestTimeout = 1000; | ||
|
||
public boolean isEnabled() { | ||
return enabled; | ||
} | ||
|
||
public void setEnabled(final boolean enabled) { | ||
this.enabled = enabled; | ||
} | ||
|
||
public long getTenantCacheTtl() { | ||
return tenantCacheTtl; | ||
} | ||
|
||
public void setTenantCacheTtl(final long tenantCacheTtl) { | ||
this.tenantCacheTtl = tenantCacheTtl; | ||
} | ||
|
||
public long getTenantCacheSize() { | ||
return tenantCacheSize; | ||
} | ||
|
||
public void setTenantCacheSize(final long tenantCacheSize) { | ||
this.tenantCacheSize = tenantCacheSize; | ||
} | ||
|
||
public int getTenantRequestCapacity() { | ||
return tenantRequestCapacity; | ||
} | ||
|
||
public void setTenantRequestCapacity(final int tenantRequestCapacity) { | ||
this.tenantRequestCapacity = tenantRequestCapacity; | ||
} | ||
|
||
public long getTenantRequestTimeout() { | ||
return tenantRequestTimeout; | ||
} | ||
|
||
public void setTenantRequestTimeout(final long tenantRequestTimeout) { | ||
this.tenantRequestTimeout = tenantRequestTimeout; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash( | ||
enabled, tenantCacheTtl, tenantCacheSize, tenantRequestCapacity, tenantRequestTimeout); | ||
} | ||
|
||
@Override | ||
public boolean equals(final Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
final IdentityServiceCfg that = (IdentityServiceCfg) o; | ||
return enabled == that.enabled | ||
&& tenantCacheTtl == that.tenantCacheTtl | ||
&& tenantCacheSize == that.tenantCacheSize | ||
&& tenantRequestCapacity == that.tenantRequestCapacity | ||
&& tenantRequestTimeout == that.tenantRequestTimeout; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "IdentityRequestCfg{" | ||
+ "enabled=" | ||
+ enabled | ||
+ ", tenantCacheTtl=" | ||
+ tenantCacheTtl | ||
+ ", tenantCacheSize=" | ||
+ tenantCacheSize | ||
+ ", tenantRequestCapacity=" | ||
+ tenantRequestCapacity | ||
+ ", tenantRequestTimeout=" | ||
+ tenantRequestTimeout | ||
+ '}'; | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
gateway/src/main/java/io/camunda/zeebe/gateway/impl/identity/IdentityTenantService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under | ||
* one or more contributor license agreements. See the NOTICE file distributed | ||
* with this work for additional information regarding copyright ownership. | ||
* Licensed under the Zeebe Community License 1.1. You may not use this file | ||
* except in compliance with the Zeebe Community License 1.1. | ||
*/ | ||
package io.camunda.zeebe.gateway.impl.identity; | ||
|
||
import com.google.common.cache.CacheBuilder; | ||
import com.google.common.cache.CacheLoader; | ||
import com.google.common.cache.LoadingCache; | ||
import io.camunda.identity.sdk.Identity; | ||
import io.camunda.identity.sdk.tenants.dto.Tenant; | ||
import io.camunda.zeebe.gateway.cmd.ConcurrentRequestException; | ||
import io.camunda.zeebe.gateway.impl.configuration.IdentityServiceCfg; | ||
import java.util.List; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.Semaphore; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
public class IdentityTenantService { | ||
|
||
private static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS; | ||
|
||
private final LoadingCache<String, List<Tenant>> tenantCache; | ||
private final Semaphore semaphore; | ||
private final Identity identity; | ||
|
||
private final boolean isCachingEnabled; | ||
private final long tenantRequestTimeout; | ||
|
||
public IdentityTenantService(final Identity identity, final IdentityServiceCfg config) { | ||
this.identity = identity; | ||
isCachingEnabled = config.isEnabled(); | ||
tenantRequestTimeout = config.getTenantRequestTimeout(); | ||
semaphore = new Semaphore(config.getTenantRequestCapacity()); | ||
tenantCache = | ||
CacheBuilder.newBuilder() | ||
.expireAfterWrite(config.getTenantCacheTtl(), TIME_UNIT) | ||
.maximumSize(config.getTenantCacheSize()) | ||
.build( | ||
new CacheLoader<>() { | ||
@Override | ||
public List<Tenant> load(final String token) { | ||
return getTenantsForTokenThrottled(token); | ||
} | ||
}); | ||
} | ||
|
||
public List<Tenant> getTenantsForToken(final String token) throws ExecutionException { | ||
if (!isCachingEnabled) { | ||
return getTenantsForTokenInternal(token); | ||
} | ||
return tenantCache.get(token); | ||
} | ||
|
||
private List<Tenant> getTenantsForTokenThrottled(final String token) { | ||
try { | ||
if (!semaphore.tryAcquire(tenantRequestTimeout, TIME_UNIT)) { | ||
throw new ConcurrentRequestException(tenantRequestTimeout, TIME_UNIT); | ||
} | ||
return getTenantsForTokenInternal(token); | ||
} catch (final InterruptedException e) { | ||
Thread.currentThread().interrupt(); | ||
throw new RuntimeException( | ||
"Expected to fetch tenants from Identity, but the request was interrupted", e); | ||
} finally { | ||
semaphore.release(); | ||
} | ||
} | ||
|
||
private List<Tenant> getTenantsForTokenInternal(final String token) { | ||
return identity.tenants().forToken(token); | ||
} | ||
} |
Oops, something went wrong.