Skip to content

Commit

Permalink
Do not attempt to access the request context in Fallback callback. If…
Browse files Browse the repository at this point in the history
… used together with Retry, it is possible for the fallback to be called in a fresh thread for which there is no current request scope. Instead just use the original value obtained in this class' constructor. Updated functional test (with some class renaming) to cover this use case. (#2748)

Signed-off-by: Santiago Pericasgeertsen <santiago.pericasgeertsen@oracle.com>
  • Loading branch information
spericas authored Feb 9, 2021
1 parent e724d2c commit 4c74ff0
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -587,21 +587,9 @@ private FtHandlerTyped<Object> createMethodHandler(MethodState methodState) {
if (introspector.hasFallback()) {
Fallback<Object> fallback = Fallback.builder()
.fallback(throwable -> {
try {
// Reference request context if request scope is active
if (requestScope != null) {
requestContext = requestScope.referenceCurrent();
}

// Execute callback logic
CommandFallback cfb = new CommandFallback(context, introspector, throwable);
return toCompletionStageSupplier(cfb::execute).get();
} finally {
// Release request context if referenced
if (requestContext != null) {
requestContext.release();
}
}
// Execute callback logic
CommandFallback cfb = new CommandFallback(context, introspector, throwable);
return toCompletionStageSupplier(cfb::execute).get();
})
.applyOn(mapTypes(introspector.getFallback().applyOn()))
.skipOn(mapTypes(introspector.getFallback().skipOn()))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,11 +21,11 @@
import org.eclipse.microprofile.faulttolerance.Retry;

@ApplicationScoped
public class SomeService {
public class Bean1 {

@Inject
@TestQualifier
RequestTestQualifier requestTestQualifier;
private RequestTestQualifier requestTestQualifier;

@Retry
public String test() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,20 +15,21 @@
*/
package io.helidon.tests.functional.requestscope;

import java.util.concurrent.atomic.AtomicLong;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.concurrent.atomic.AtomicLong;

import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
import org.eclipse.microprofile.faulttolerance.Fallback;

@ApplicationScoped
public class SomeService2 {
public class Bean2 {

private AtomicLong counter = new AtomicLong(0);

@Inject
TenantContext tenantContext;
private TenantContext tenantContext;

@CircuitBreaker(successThreshold = 2, requestVolumeThreshold = 4)
@Fallback(fallbackMethod = "testFallback")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,13 +15,14 @@
*/
package io.helidon.tests.functional.requestscope;

import javax.enterprise.context.ApplicationScoped;
import java.util.concurrent.atomic.AtomicLong;

import javax.enterprise.context.ApplicationScoped;

import org.eclipse.microprofile.faulttolerance.Fallback;

@ApplicationScoped
public class SomeService3 {
public class Bean3 {

private AtomicLong counter = new AtomicLong(0);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.tests.functional.requestscope;

import java.util.concurrent.atomic.AtomicLong;

import javax.enterprise.context.ApplicationScoped;

import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.Retry;

@ApplicationScoped
public class Bean4 {

private AtomicLong counter = new AtomicLong(0);

@Retry(jitter = 1000L, delay = 3)
@Fallback(fallbackMethod = "testFallback")
public String test(String testParam) throws Exception {
throw new RuntimeException("called failed");
}

public String testFallback(String testParam) throws Exception {
return testParam;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,15 +24,15 @@

@RequestScoped
@Path("/test")
public class MultiTenantService {
public class Service1 {

@Inject
SomeService someService;
private Bean1 bean1;

@GET
public String getTenantResource() {
try {
return someService.test();
return bean1.test();
} catch (IllegalTenantException e) {
return "Expected";
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,15 +24,15 @@

@RequestScoped
@Path("/test2")
public class MultiTenantService2 {
public class Service2 {

@Inject
SomeService2 someService2;
private Bean2 bean2;

@GET
public String getTenantResource() {
try {
String s = someService2.test();
String s = bean2.test();
return s == null ? "" : s;
} catch (Exception e) {
// This path implies a CDI exception related to request scope
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -25,19 +25,18 @@

@RequestScoped
@Path("/test3")
public class MyResource {
public class Service3 {

@Inject
SomeService3 someService3;
private Bean3 bean3;

@GET
public String getTestResource(@QueryParam("param1") String param1) {
try {
return someService3.test(param1);
return bean3.test(param1);
} catch (Exception e) {
System.out.println(e.getMessage());
throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.tests.functional.requestscope;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;

@RequestScoped
@Path("/test4")
public class Service4 {

@Inject
private Bean4 bean4;

@GET
public String getTestResource(@QueryParam("param1") String param1) {
try {
return bean4.test(param1);
} catch (Exception e) {
System.out.println(e.getMessage());
throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -66,4 +66,16 @@ public void test3() {
assertThat(entityValue, is(paramValue));
}
}

@Test
public void test4() {
Response r;
r = baseTarget.path("test4")
.queryParam("param1", "1")
.request()
.get();
assertThat(r.getStatus(), is(HttpResponseStatus.OK.code()));
String entityValue = r.readEntity(String.class);
assertThat(entityValue, is("1"));
}
}

0 comments on commit 4c74ff0

Please sign in to comment.