Working with Timeout

Optimization models are often so complex that they require quite a bit of time to find a good solution, or even a feasible one. It is the same case for solving VRPs. For the Cloud Fleet Routing service, we provide the options for users to specify the time they would allow our server to consume for optimization. Usually, for complex VRPs, the more time the solver takes, the more accurate the results returned.

When sending a request to the Cloud Fleet Routing service, it is good to know how to properly set it up, so that the user can get an ideal solution in time. Google provides both the synchronous and asynchronous methods for optimizing tours, and users can call our API using different approaches, for example, through direct HTTP calls versus through using client libraries. It is worth clarifying how to properly configure the time limit in each setting, and which approach to choose based on users' preferences of getting a solution as soon as possible or getting a solution with better quality.

General guidance

To help you decide which method to use, consider the following general guidance:

  • If your application is time sensitive of getting a solution, use the synchronous method and set the timeout value properly.
  • If you would like to spend more time and get a better quality solution, use the asynchronous method and set the timeout value properly.
  • For both methods, the longest supported time for solving the model is 30 minutes with allowLargeDeadlineDespiteInterruptionRisk not set.
  • For both methods, the longest supported time for solving the model is 60 minutes with allowLargeDeadlineDespiteInterruptionRisk set to true.

For more details about these fields, please refer to optimizeToursRequest.

How to configure a request

Call the synchronous method

For our synchronous method optimizeTours, there are two factors that affect the response time:

  • The value of the timeout field in optimizeToursRequest.
  • The time limit for connecting to our server, which is supported differently based on the approach used to call the API:
    • When making an HTTP call directly, you can set up X-Server-Timeout value in the header.
    • When using the API Client Library for Python and Java, you can set the timeout config value for the client. For your convenience, the default timeout value for both clients are set to 60 minutes, which is the longest supported response time for the synchronous method.

The server returns a solution within the limit of the minimum of the two. As mentioned earlier, if you would like to set the timeout value in optimizeToursRequest to between 30 minutes and 60 minutes, set allowLargeDeadlineDespiteInterruptionRisk to true.

If the timeout field is not set, the client deadline is directly used as the maximum time for returning a solution.

Send a synchronous request with a long timeout (Java example)

When a request might take a longer time to solve, we recommend using the asynchronous API. However, if you prefer, you can still send a synchronous request with a long timeout.

If you run the client on a Compute Engine virtual machine (VM), the firewall will end connections that are idle for a long time. The keep-alive setting forces the client to ping the API server to keep the connection alive. We recommend a five-minute keep-alive setting, but you can adjust this value based on your use case. As an example, the following code sends a request with payload in the request.textproto file to the Cloud Fleet Routing optimizeTours method, while setting up the checks to keep the connection alive.

Java

Before trying this sample, follow the setup instructions for this language on the Quickstarts > Using the client libraries page.


import com.google.cloud.optimization.v1.FleetRoutingClient;
import com.google.cloud.optimization.v1.FleetRoutingSettings;
import com.google.cloud.optimization.v1.OptimizeToursRequest;
import com.google.cloud.optimization.v1.OptimizeToursResponse;
import com.google.protobuf.Duration;
import com.google.protobuf.TextFormat;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

/**
 * This is an example to send a request to Cloud Fleet Routing synchronous API via Java API Client.
 */
public class SyncApiWithLongTimeout {
  public static void longTimeout() throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectParent = "projects/{YOUR_GCP_PROJECT_ID}";
    String modelPath = "YOUR_MODEL_PATH";
    longTimeout(projectParent, modelPath);
  }

  public static void longTimeout(String projectParent, String modelPath) throws Exception {
    int timeoutSeconds = 100;
    InputStream modelInputstream = new FileInputStream(modelPath);
    Reader modelInputStreamReader = new InputStreamReader(modelInputstream);
    OptimizeToursRequest.Builder requestBuilder =
        OptimizeToursRequest.newBuilder()
            .setTimeout(Duration.newBuilder().setSeconds(timeoutSeconds).build())
            .setParent(projectParent);
    TextFormat.getParser().merge(modelInputStreamReader, requestBuilder);

    // Checks the gRPC connection every 5 mins and keeps it alive.
    FleetRoutingClient fleetRoutingClientClient =
        FleetRoutingClient.create(
            FleetRoutingSettings.newBuilder()
                .setTransportChannelProvider(
                    FleetRoutingSettings.defaultGrpcTransportProviderBuilder()
                        .setKeepAliveTime(org.threeten.bp.Duration.ofSeconds(300))
                        .build())
                .build());
    OptimizeToursResponse response = fleetRoutingClientClient.optimizeTours(requestBuilder.build());
    System.out.println(response.toString());
  }
}

Python

Before trying this sample, follow the setup instructions for this language on the Quickstarts > Using the client libraries page.


from google.cloud import optimization_v1
from google.cloud.optimization_v1.services import fleet_routing
from google.cloud.optimization_v1.services.fleet_routing import transports
from google.cloud.optimization_v1.services.fleet_routing.transports import (
    grpc as fleet_routing_grpc,
)

# TODO(developer): Uncomment these variables before running the sample.
# project_id= 'YOUR_PROJECT_ID'


def long_timeout(request_file_name: str, project_id: str) -> None:
    with open(request_file_name) as f:
        fleet_routing_request = optimization_v1.OptimizeToursRequest.from_json(f.read())
        fleet_routing_request.parent = f"projects/{project_id}"

    # Create a channel to provide a connection to the Fleet Routing servers with
    # custom behavior. The `grpc.keepalive_time_ms` channel argument modifies
    # the channel behavior in order to send keep-alive pings every 5 minutes.
    channel = fleet_routing_grpc.FleetRoutingGrpcTransport.create_channel(
        options=[
            ("grpc.keepalive_time_ms", 500),
            ("grpc.max_send_message_length", -1),
            ("grpc.max_receive_message_length", -1),
        ],
    )
    # Keep-alive pings are sent on the transport. Create the transport using the
    # custom channel The transport is essentially a wrapper to the channel.
    transport = transports.FleetRoutingGrpcTransport(channel=channel)
    client = fleet_routing.client.FleetRoutingClient(transport=transport)
    fleet_routing_response = client.optimize_tours(fleet_routing_request)
    print(fleet_routing_response)

Call the asynchronous method

For our asynchronous method batchOptimizeTours, the time required for returning a solution depends on the timeout field in the optimizeToursRequest read from the storage, plus the time your request is queued in our service. In other words, the value of timeout sets the deadline for our server to solve your VRP model, but you might wait a bit longer (usually a few more seconds to minutes) to receive your solution. We recommend that you use the asynchronous method when you want to spend more time solving the model and your application is not particularly time sensitive in receiving the solution.

As mentioned earlier, if you would like to set the timeout value between 30 minutes and 60 minutes, set allowLargeDeadlineDespiteInterruptionRisk to true.

If the timeout field is not set, a default value of 30 minutes is used.