forked from mercedes-benz/sechub
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented simple resilience approach and handle now 400 retry merce…
…des-benz#100 - Introducing a simple resilience approach (which can handle retry and fall through mechanism, but we currently have only one retry mechanism) - having a 400 BAD request on a checkmarx scan upload can be resulted by an internal server error on checkmarx side. Normally this only happens in test scenarios, but wanted to have this stable. So an automated retry is triggered 3 times before throwing an exception now
- Loading branch information
Showing
20 changed files
with
781 additions
and
41 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
32 changes: 32 additions & 0 deletions
32
sechub-doc/src/docs/asciidoc/diagrams/diagram_simple_resilience.plantuml
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,32 @@ | ||
interface ResilienceConsultant{ | ||
{method} proposalFor (ResilienceContext): ResilienceProposal | ||
} | ||
interface ResilienceContext | ||
|
||
interface ResilienceProposal | ||
|
||
interface RetryResilienceProposal extends ResilienceProposal{ | ||
{method} int getMaximumAmountOfRetries | ||
{method} int getMillisecondsToWaitBeforeRetry | ||
} | ||
|
||
interface FallThroughResilienceProposal extends ResilienceProposal{ | ||
{method} int getMillisecondsForFallThrough | ||
} | ||
|
||
interface ActionWhichShallBeResilient{ | ||
<R> execute() throws Exception | ||
} | ||
|
||
class ResilientActionExecutor | ||
|
||
ResilienceConsultant .. ResilienceContext | ||
ResilientActionExecutor --> "creates" ResilienceContext | ||
|
||
ResilienceConsultant ..> "returns" ResilienceProposal | ||
|
||
|
||
ResilientActionExecutor "1" -- "0..*" ResilienceConsultant | ||
ResilientActionExecutor --> "inspects" ResilienceProposal | ||
|
||
ResilientActionExecutor --> "executes" ActionWhichShallBeResilient |
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
18 changes: 18 additions & 0 deletions
18
...-doc/src/docs/asciidoc/documents/shared/concepts/concept_simple_resilience.adoc
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,18 @@ | ||
We do currently not use Hystrix or another framework to handle resilience, | ||
but use a simple own approach: | ||
|
||
plantuml::./diagrams/diagram_simple_resilience.plantuml[] | ||
|
||
A resilient action executor can be used to execute a dedicated | ||
action. Implementation of `ResilienctConsultant` will give | ||
dedicated proposals how to handle an error. | ||
|
||
There are currently two different ways: | ||
|
||
- Retry + | ||
In this case the failed action will be retried some times | ||
before the exception is thrown | ||
- Fall through + | ||
Here the failure is recognized as a situation which will be | ||
happen very often because a fix will take some time and so | ||
to fail fast for a given time period instead of blocking |
34 changes: 34 additions & 0 deletions
34
.../java/com/daimler/sechub/domain/scan/product/checkmarx/CheckmarxBadRequestConsultant.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,34 @@ | ||
package com.daimler.sechub.domain.scan.product.checkmarx; | ||
|
||
import java.util.Objects; | ||
|
||
import org.springframework.web.client.HttpClientErrorException; | ||
|
||
import com.daimler.sechub.sharedkernel.resilience.ResilienceConsultant; | ||
import com.daimler.sechub.sharedkernel.resilience.ResilienceContext; | ||
import com.daimler.sechub.sharedkernel.resilience.ResilienceProposal; | ||
import com.daimler.sechub.sharedkernel.resilience.SimpleRetryResilienceProposal; | ||
import com.daimler.sechub.sharedkernel.util.StacktraceUtil; | ||
|
||
public class CheckmarxBadRequestConsultant implements ResilienceConsultant { | ||
|
||
@Override | ||
public ResilienceProposal consultFor(ResilienceContext context) { | ||
Objects.requireNonNull(context); | ||
Throwable rootCause = StacktraceUtil.findRootCause(context.getCurrentError()); | ||
if (rootCause instanceof HttpClientErrorException) { | ||
HttpClientErrorException hce = (HttpClientErrorException) rootCause; | ||
int statusCode = hce.getRawStatusCode(); | ||
if (statusCode == 400) { | ||
/* | ||
* BAD request - this can happen for same project scans put to queue because | ||
* there can a chmkx server error happen | ||
*/ | ||
return new SimpleRetryResilienceProposal("checkmarx bad request handling", 3, 2000); | ||
|
||
} | ||
} | ||
return null; | ||
} | ||
|
||
} |
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
65 changes: 65 additions & 0 deletions
65
...a/com/daimler/sechub/domain/scan/product/checkmarx/CheckmarxBadRequestConsultantTest.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,65 @@ | ||
package com.daimler.sechub.domain.scan.product.checkmarx; | ||
|
||
import static org.junit.Assert.*; | ||
import static org.mockito.Mockito.*; | ||
|
||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.client.HttpClientErrorException; | ||
|
||
import com.daimler.sechub.sharedkernel.resilience.ResilienceContext; | ||
import com.daimler.sechub.sharedkernel.resilience.ResilienceProposal; | ||
import com.daimler.sechub.sharedkernel.resilience.RetryResilienceProposal; | ||
|
||
public class CheckmarxBadRequestConsultantTest { | ||
|
||
private CheckmarxBadRequestConsultant consultantToTest; | ||
private ResilienceContext context; | ||
|
||
@Before | ||
public void before() { | ||
consultantToTest = new CheckmarxBadRequestConsultant(); | ||
context= mock(ResilienceContext.class); | ||
} | ||
|
||
@Test | ||
public void no_exception_returns_null() { | ||
/* prepare*/ | ||
|
||
/* execute*/ | ||
ResilienceProposal proposal = consultantToTest.consultFor(context); | ||
|
||
/* test*/ | ||
assertNull(proposal); | ||
} | ||
|
||
@Test | ||
public void illegal_argument_exception_returns_null() { | ||
/* prepare*/ | ||
when(context.getCurrentError()).thenReturn(new IllegalArgumentException()); | ||
|
||
/* execute*/ | ||
ResilienceProposal proposal = consultantToTest.consultFor(context); | ||
|
||
/* test*/ | ||
assertNull(proposal); | ||
} | ||
|
||
@Test | ||
public void http_bad_request_400_exception_returns_retry_proposal_with_3_retries_and_2000_millis_to_wait() { | ||
/* prepare*/ | ||
when(context.getCurrentError()).thenReturn(new HttpClientErrorException(HttpStatus.BAD_REQUEST)); | ||
|
||
/* execute*/ | ||
ResilienceProposal proposal = consultantToTest.consultFor(context); | ||
|
||
/* test*/ | ||
assertNotNull(proposal); | ||
assertTrue(proposal instanceof RetryResilienceProposal); | ||
RetryResilienceProposal rrp = (RetryResilienceProposal) proposal; | ||
assertEquals(3, rrp.getMaximumAmountOfRetries()); | ||
assertEquals(2000, rrp.getMillisecondsToWaitBeforeRetry()); | ||
} | ||
|
||
} |
27 changes: 27 additions & 0 deletions
27
...t/java/com/daimler/sechub/domain/scan/product/checkmarx/CheckmarxProductExecutorTest.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,27 @@ | ||
package com.daimler.sechub.domain.scan.product.checkmarx; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
public class CheckmarxProductExecutorTest { | ||
|
||
private CheckmarxProductExecutor executorToTest; | ||
|
||
@Before | ||
public void before() { | ||
executorToTest= new CheckmarxProductExecutor(); | ||
} | ||
|
||
@Test | ||
public void action_executor_is_not_null() { | ||
assertNotNull(executorToTest.resilientActionExecutor); | ||
} | ||
|
||
@Test | ||
public void action_executor_contains_checkmarx_bad_request_consultant() { | ||
assertTrue(executorToTest.resilientActionExecutor.containsConsultant(CheckmarxBadRequestConsultant.class)); | ||
} | ||
|
||
} |
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
11 changes: 11 additions & 0 deletions
11
...src/main/java/com/daimler/sechub/sharedkernel/resilience/ActionWhichShallBeResilient.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,11 @@ | ||
package com.daimler.sechub.sharedkernel.resilience; | ||
|
||
public interface ActionWhichShallBeResilient<R> { | ||
|
||
/** | ||
* Action method which shall be executed in resilient way | ||
* @return | ||
* @throws Exception | ||
*/ | ||
public R execute() throws Exception; | ||
} |
16 changes: 16 additions & 0 deletions
16
...c/main/java/com/daimler/sechub/sharedkernel/resilience/FallthroughResilienceProposal.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,16 @@ | ||
package com.daimler.sechub.sharedkernel.resilience; | ||
|
||
public interface FallthroughResilienceProposal extends ResilienceProposal{ | ||
/** | ||
* | ||
*Defines the amount of time (in milliseconds) where a fall through shall | ||
*be done. This means, the current error will be simply reused and given back. | ||
*<br><br>This is interesting when having a server done, were a time out (e.g. | ||
*HTTP request) appears only a some time (e.g. 2 minutes). And we got n amount of | ||
*calls (e.g. 500...) and we do NOT want to have every call wait for 2 Minutes but | ||
*instead fail fast. So interesting in this case could be a time of 1000*60*2 to do | ||
*the fall through. | ||
* @return milliseconds where a fall through shall be done | ||
*/ | ||
public long getMillisecondsForFallThrough(); | ||
} |
Oops, something went wrong.