Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Shutdown and awaitTermination for showcase clients #1669

Merged
merged 21 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,24 @@
@BetaApi
public class ManagedHttpJsonChannel implements HttpJsonChannel, BackgroundResource {

private static final ExecutorService DEFAULT_EXECUTOR =
InstantiatingExecutorProvider.newBuilder().build().getExecutor();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static DEFAULT_EXECUTOR error'd out on the unit tests. Same executor was being used and it was shutdown after the first test.


private final Executor executor;
private final boolean usingDefaultExecutor;
private final String endpoint;
private final HttpTransport httpTransport;
private final ScheduledExecutorService deadlineScheduledExecutorService;

private boolean isTransportShutdown;

protected ManagedHttpJsonChannel() {
this(null, null, null);
this(null, true, null, null);
}

private ManagedHttpJsonChannel(
Executor executor, String endpoint, @Nullable HttpTransport httpTransport) {
Executor executor,
boolean usingDefaultExecutor,
String endpoint,
@Nullable HttpTransport httpTransport) {
this.executor = executor;
this.usingDefaultExecutor = usingDefaultExecutor;
this.endpoint = endpoint;
this.httpTransport = httpTransport == null ? new NetHttpTransport() : httpTransport;
this.deadlineScheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
Expand All @@ -84,10 +85,16 @@ public <RequestT, ResponseT> HttpJsonClientCall<RequestT, ResponseT> newCall(

@Override
public synchronized void shutdown() {
// Calling shutdown() twice should no-op
if (isTransportShutdown) {
return;
}
try {
// Only shutdown the executor if it was created by Gax. External executors
// should be managed by the user.
if (usingDefaultExecutor) {
((ExecutorService) executor).shutdown();
}
deadlineScheduledExecutorService.shutdown();
httpTransport.shutdown();
isTransportShutdown = true;
Expand All @@ -98,12 +105,20 @@ public synchronized void shutdown() {

@Override
public boolean isShutdown() {
return isTransportShutdown;
if (usingDefaultExecutor) {
return ((ExecutorService) executor).isShutdown()
&& deadlineScheduledExecutorService.isShutdown();
}
return deadlineScheduledExecutorService.isShutdown();
}

@Override
public boolean isTerminated() {
return isTransportShutdown;
if (usingDefaultExecutor) {
return ((ExecutorService) executor).isTerminated()
&& deadlineScheduledExecutorService.isTerminated();
}
return deadlineScheduledExecutorService.isTerminated();
}

@Override
Expand All @@ -113,15 +128,27 @@ public void shutdownNow() {

@Override
public boolean awaitTermination(long duration, TimeUnit unit) throws InterruptedException {
// TODO
return false;
long endTimeNanos = System.nanoTime() + unit.toNanos(duration);
long awaitTimeNanos = endTimeNanos - System.nanoTime();
// Only awaitTermination for the executor if it was created by Gax. External executors
// should be managed by the user.
if (usingDefaultExecutor && awaitTimeNanos > 0) {
boolean terminated = ((ExecutorService) executor).awaitTermination(awaitTimeNanos, unit);
if (!terminated) {
return false;
}
}
awaitTimeNanos = endTimeNanos - System.nanoTime();
return deadlineScheduledExecutorService.awaitTermination(awaitTimeNanos, unit);
}

@Override
public void close() {}
public void close() {
shutdown();
}

public static Builder newBuilder() {
return new Builder().setExecutor(DEFAULT_EXECUTOR);
return new Builder();
}

public static class Builder {
Expand All @@ -133,7 +160,7 @@ public static class Builder {
private Builder() {}

public Builder setExecutor(Executor executor) {
this.executor = executor == null ? DEFAULT_EXECUTOR : executor;
this.executor = executor;
return this;
}

Expand All @@ -150,8 +177,16 @@ public Builder setHttpTransport(HttpTransport httpTransport) {
public ManagedHttpJsonChannel build() {
Preconditions.checkNotNull(endpoint);

boolean usingDefaultExecutor = executor == null;
if (usingDefaultExecutor) {
executor = InstantiatingExecutorProvider.newBuilder().build().getExecutor();
}

return new ManagedHttpJsonChannel(
executor, endpoint, httpTransport == null ? new NetHttpTransport() : httpTransport);
executor,
usingDefaultExecutor,
endpoint,
httpTransport == null ? new NetHttpTransport() : httpTransport);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,27 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class ITBidiStreaming {

private EchoClient grpcClient;
private static EchoClient grpcClient;

@Before
public void setUp() throws Exception {
@BeforeClass
public static void createClients() throws Exception {
// Create gRPC Echo Client
grpcClient = TestClientInitializer.createGrpcEchoClient();
}

@AfterClass
public static void destroyClients() throws Exception {
grpcClient.close();
grpcClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
}

// The current implementation of BIDI streaming on Echo showcase server is that it would echo the
// request content back on every request, so this test verifies that the response content is
// exactly the same as request content.
Expand Down Expand Up @@ -97,9 +104,4 @@ public SettableApiFuture<List<String>> getFuture() {
return future;
}
}

@After
public void tearDown() throws Exception {
grpcClient.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,25 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.After;
import org.junit.Before;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class ITClientSideStreaming {

private EchoClient grpcClient;
private static EchoClient grpcClient;

@Before
public void createClients() throws Exception {
@BeforeClass
public static void createClients() throws Exception {
// Create gRPC Echo Client
grpcClient = TestClientInitializer.createGrpcEchoClient();
}

@After
public void destroyClient() {
@AfterClass
public static void destroyClients() throws InterruptedException {
grpcClient.close();
grpcClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import com.google.showcase.v1beta1.it.util.TestClientInitializer;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class ITCommonServiceMixins {
Expand All @@ -51,18 +53,28 @@ public class ITCommonServiceMixins {
.setName("projects/showcase/locations/us-west")
.setDisplayName("us-west")
.build());
private EchoClient grpcClient;
private EchoClient httpjsonClient;
private static EchoClient grpcClient;
private static EchoClient httpjsonClient;

@Before
public void createClients() throws Exception {
@BeforeClass
public static void createClients() throws Exception {
// Create gRPC Echo Client
grpcClient = TestClientInitializer.createGrpcEchoClient();

// Create HttpJson Echo Client
httpjsonClient = TestClientInitializer.createHttpJsonEchoClient();
}

@AfterClass
public static void destroyClients() throws InterruptedException {
grpcClient.close();
httpjsonClient.close();

grpcClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
httpjsonClient.awaitTermination(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is not implemented yet #1663

TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
}

@Test
public void testGrpc_getLocation() {
GetLocationRequest request =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
import com.google.showcase.v1beta1.it.util.TestClientInitializer;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class ITCrud {
Expand All @@ -44,24 +46,38 @@ public class ITCrud {
.setAge(25)
.build();

private IdentityClient grpcClient;
private IdentityClient httpJsonClient;
private static IdentityClient grpcClient;
private static IdentityClient httpjsonClient;

@Before
public void setup() throws Exception {
@BeforeClass
public static void createClients() throws Exception {
// Create gRPC IdentityClient
grpcClient = TestClientInitializer.createGrpcIdentityClient();
// Create HttpJson IdentityClient
httpJsonClient = TestClientInitializer.createHttpJsonIdentityClient();

// Ensure an empty state before each run
cleanupData(httpJsonClient);
httpjsonClient = TestClientInitializer.createHttpJsonIdentityClient();
}

@After
public void cleanup() {
@AfterClass
public static void destroyClients() throws InterruptedException {
grpcClient.close();
httpJsonClient.close();
httpjsonClient.close();

grpcClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
httpjsonClient.awaitTermination(
TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
}

@Before
public void cleanupData() {
IdentityClient.ListUsersPagedResponse pagedResponse =
grpcClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
for (IdentityClient.ListUsersPage listUsersPage : pagedResponse.iteratePages()) {
for (User user : listUsersPage.getResponse().getUsersList()) {
grpcClient.deleteUser(user.getName());
}
}
pagedResponse = httpjsonClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
assertThat(pagedResponse.getPage().getResponse().getUsersList().size()).isEqualTo(0);
}

@Test
Expand Down Expand Up @@ -95,7 +111,7 @@ public void testHttpJson_Read() {
.build()));
// Assert that only one User exists
IdentityClient.ListUsersPagedResponse listUsersPagedResponse =
httpJsonClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
httpjsonClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
ListUsersResponse listUsersResponse = listUsersPagedResponse.getPage().getResponse();
assertThat(listUsersResponse.getUsersList().size()).isEqualTo(2);

Expand All @@ -105,7 +121,7 @@ public void testHttpJson_Read() {

// Get User
User defaultUser = expectedUsersList.get(0);
User getUserResponse = httpJsonClient.getUser(defaultUser.getName());
User getUserResponse = httpjsonClient.getUser(defaultUser.getName());
assertThat(getUserResponse).isEqualTo(defaultUser);
}

Expand All @@ -124,7 +140,7 @@ public void testHttpJson_Update() {
.setEnableNotifications(true)
.build();
User updateUserResponse =
httpJsonClient.updateUser(
httpjsonClient.updateUser(
UpdateUserRequest.newBuilder()
.setUser(updateUser)
.setUpdateMask(
Expand All @@ -148,26 +164,14 @@ public void testHttpJson_Update() {
public void testHttpJson_Delete() {
User userResponse = createDefaultUser();

httpJsonClient.deleteUser(
httpjsonClient.deleteUser(
DeleteUserRequest.newBuilder().setName(userResponse.getName()).build());

IdentityClient.ListUsersPagedResponse listUsersPagedResponse =
httpJsonClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
httpjsonClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
assertThat(listUsersPagedResponse.getPage().getResponse().getUsersList().size()).isEqualTo(0);
}

private void cleanupData(IdentityClient identityClient) {
IdentityClient.ListUsersPagedResponse pagedResponse =
identityClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
for (IdentityClient.ListUsersPage listUsersPage : pagedResponse.iteratePages()) {
for (User user : listUsersPage.getResponse().getUsersList()) {
identityClient.deleteUser(user.getName());
}
}
pagedResponse = httpJsonClient.listUsers(ListUsersRequest.newBuilder().setPageSize(5).build());
assertThat(pagedResponse.getPage().getResponse().getUsersList().size()).isEqualTo(0);
}

private User createDefaultUser() {
return createUser(DEFAULT_USER);
}
Expand All @@ -182,6 +186,6 @@ private User createDefaultUser() {
* @return newly created user
*/
private User createUser(User user) {
return httpJsonClient.createUser(CreateUserRequest.newBuilder().setUser(user).build());
return httpjsonClient.createUser(CreateUserRequest.newBuilder().setUser(user).build());
}
}