Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,20 @@ java_binary(
],
)

java_binary(
name = "deadline-server",
testonly = 1,
main_class = "io.grpc.examples.deadline.DeadlineServer",
runtime_deps = [
":examples",
],
)

java_binary(
name = "deadline-client",
testonly = 1,
main_class = "io.grpc.examples.deadline.DeadlineClient",
runtime_deps = [
":examples",
],
)
16 changes: 16 additions & 0 deletions examples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,27 @@ task nameResolveClient(type: CreateStartScripts) {
classpath = startScripts.classpath
}

task deadlineServer(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.deadline.DeadlineServer'
applicationName = 'deadline-server'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task keepAliveServer(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.keepalive.KeepAliveServer'
applicationName = 'keep-alive-server'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task deadlineClient(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.deadline.DeadlineClient'
applicationName = 'deadline-client'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task keepAliveClient(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.keepalive.KeepAliveClient'
applicationName = 'keep-alive-client'
Expand All @@ -197,6 +211,8 @@ applicationDistribution.into('bin') {
from(loadBalanceClient)
from(nameResolveServer)
from(nameResolveClient)
from(deadlineServer)
from(deadlineClient)
from(keepAliveServer)
from(keepAliveClient)
fileMode = 0755
Expand Down
110 changes: 110 additions & 0 deletions examples/src/main/java/io/grpc/examples/deadline/DeadlineClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright 2023 The gRPC Authors
*
* 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.grpc.examples.deadline;

import io.grpc.Channel;
import io.grpc.Grpc;
import io.grpc.InsecureChannelCredentials;
import io.grpc.ManagedChannel;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.examples.helloworld.HelloWorldServer;
import java.util.concurrent.TimeUnit;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

/**
* A simple client that requests a greeting from the {@link HelloWorldServer}.
*
* <p>This is based off the client in the helloworld example with some deadline logic added.
*/
public class DeadlineClient {
private static final Logger logger = Logger.getLogger(DeadlineClient.class.getName());

private final GreeterGrpc.GreeterBlockingStub blockingStub;

/** Construct client for accessing HelloWorld server using the existing channel. */
public DeadlineClient(Channel channel) {
blockingStub = GreeterGrpc.newBlockingStub(channel);
}

/** Say hello to server. */
public Status greet(String name, long timeoutMillis) {
logger.info("Will try to greet " + name + " ...");
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response;
try {
response = blockingStub.withDeadlineAfter(timeoutMillis, TimeUnit.MILLISECONDS)
.sayHello(request);
} catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
return e.getStatus();
}
logger.info("Greeting: " + response.getMessage());
return Status.OK;
}

/**
* Greet server. If provided, the first element of {@code args} is the name to use in the
* greeting. The second argument is the target server.
*/
public static void main(String[] args) throws Exception {
System.setProperty("java.util.logging.SimpleFormatter.format",
"%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n");

// Access a service running on the local machine on port 50051
String target = "localhost:50051";

ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create())
.build();
try {
DeadlineClient client = new DeadlineClient(channel);

// The server takes 500ms to process the call, so setting a deadline further in the future we
// should get a successful response.
logger.info("Calling server with a generous deadline, expected to work");
client.greet("deadline client", 1000);

// A smaller deadline will result in us getting a DEADLINE_EXCEEDED error.
logger.info(
"Calling server with an unrealistic (300ms) deadline, expecting a DEADLINE_EXCEEDED");
client.greet("deadline client", 300);

// Including the "propagate" magic string in the request will cause the server to call itself
// to simulate a situation where a server needs to call another server to satisfy the original
// request. This will double the time it takes to respond to the client request, but with
// an increased deadline we should get a successful response.
logger.info("Calling server with propagation and a generous deadline, expected to work");
client.greet("deadline client [propagate]", 2000);

// With this propagated call we reduce the deadline making it impossible for the both the
// first server call and the propagated one to succeed. You should see the call fail with
// DEADLINE_EXCEEDED, and you should also see DEADLINE_EXCEEDED in the server output as it
// runs out of time waiting for the propagated call to finish.
logger.info(
"Calling server with propagation and a generous deadline, expecting a DEADLINE_EXCEEDED");
client.greet("deadline client [propagate]", 1000);
} finally {
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
}
119 changes: 119 additions & 0 deletions examples/src/main/java/io/grpc/examples/deadline/DeadlineServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@

/*
* Copyright 2023 The gRPC Authors
*
* 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.grpc.examples.deadline;

import io.grpc.Grpc;
import io.grpc.InsecureChannelCredentials;
import io.grpc.InsecureServerCredentials;
import io.grpc.Server;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class DeadlineServer {
private static final Logger logger = Logger.getLogger(DeadlineServer.class.getName());

private Server server;


private void start() throws IOException {
int port = 50051;
SlowGreeter slowGreeter = new SlowGreeter();
server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
.addService(slowGreeter)
.build()
.start();
logger.info("Server started, listening on " + port);

// Create a channel to this same server so we can make a recursive call to demonstrate deadline
// propagation.
String target = "localhost:50051";
slowGreeter.setClientStub(GreeterGrpc.newBlockingStub(
Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()).build()));

Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
// Use stderr here since the logger may have been reset by its JVM shutdown hook.
System.err.println("*** shutting down gRPC server since JVM is shutting down");
try {
DeadlineServer.this.stop();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
System.err.println("*** server shut down");
}
});
}

private void stop() throws InterruptedException {
if (server != null) {
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
}
}

/**
* Await termination on the main thread since the grpc library uses daemon threads.
*/
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}

/**
* Main launches the server from the command line.
*/
public static void main(String[] args) throws IOException, InterruptedException {
System.setProperty("java.util.logging.SimpleFormatter.format",
"%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n");

final DeadlineServer server = new DeadlineServer();
server.start();
server.blockUntilShutdown();
}

static class SlowGreeter extends GreeterGrpc.GreeterImplBase {
private GreeterGrpc.GreeterBlockingStub clientStub;

void setClientStub(GreeterGrpc.GreeterBlockingStub clientStub) {
this.clientStub = clientStub;
}

@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}

if (req.getName().contains("propagate")) {
clientStub.sayHello(HelloRequest.newBuilder().setName("Server").build());
}

HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}