Skip to content

Changing Timeouts

Stu Arnett edited this page Mar 12, 2021 · 8 revisions

WARNING

Before reading further, it is important to point out the inherent risks of using client request timeouts.

Versions 3.1.3 and below have read timeout defaulted to 1 minute, which has potential risk (see below).
Versions 3.2.0 and above are defaulted to off.

Lost Update Problem

The S3 protocol does not provide any transaction semantics outside of a single request. With this in mind, if a client PUT request times out, it is very possible (likely in fact) that this request will eventually execute on the server side. So whenever you use a client timeout, you must be aware of the possibility of delayed execution on any timed out request. This could lead to lost updates. For example, imagine the following scenario:

  1. client executes PUT /bucket1/object1 {X}
  2. request times out
  3. client retries PUT /bucket1/object1 {X}
  4. request succeeds
  5. client sends update PUT /bucket1/object1 {X2}
  6. request succeeds
  7. original PUT completes execution on ECS
  8. state of /bucket1/object1 is now {X} (the update {X2} is lost)

Using Pre-conditions as Optimistic Locks (available with ECS 3.5 and above)

One way to mitigate this risk is to use pre-conditions on your requests as an optimistic lock. For example, in the scenario above, assuming you know that the original PUT request for /bucket1/object1 will create the object (it should not exist prior), then you can set the If-None-Match header to "*". This pre-condition states that the request should only execute if the object does not exist. If we had applied that precondition to the first PUT above, then when it finally executes on ECS (step 7), it would fail because the object has already been created, and {X2} would remain the current state as expected.

Similarly, if you cache the ETag of the object after each PUT, you can set the If-Match header to that ETag on subsequent PUTs. This pre-condition states that the request should only execute if the object is in the state you expect it to be (having that ETag or MD5). In the example above, we could add that pre-condition to step 5, and if that step times out, it will only execute on ECS if the object hasn't changed since we first sent the request. This would avoid any lost updates that happen after {X2}.

Setting the Client Timeout

Versions 3.1.3 and below:

The default read timeout for the client is 60 seconds and the default connect timeout is 15 seconds. In some cases, you may need to increase that (for example, if you are issuing a large multi-delete call or a call that may take longer than 60 seconds). To change the timeouts, set the following properties on the S3Config instance passed to the client constructor:

S3Config s3Config = ...
// set connect timeout:
s3config.setProperty(ClientConfig.PROPERTY_CONNECT_TIMEOUT, 30000); // value is MS
// set read timeout (for long-running calls) - set to 0 to disable:
s3config.setProperty(ClientConfig.PROPERTY_READ_TIMEOUT, 300000); // value is MS

S3Client s3Client = new S3JerseyClient(s3Config);

Versions 3.2.0 and above (default read timeout is disabled):

S3Config s3Config = ...
// set connect timeout:
s3config.setConnectTimeout(30000); // value is MS
// set read timeout (for long-running calls) - set to 0 to disable:
s3config.setReadTimeout(300000); // value is MS

S3Client s3Client = new S3JerseyClient(s3Config);