9.10 Timeouts
Timeouts occur when an operation returns before its completion because the maximum time allocated for the operation (timeout time) has elapsed. The user often specifies the timeout time. For example, it might take a form of a parameter to a method call.
server.PerformOperation(timeout);
An alternative approach is to use a property.
server.Timeout = timeout; server.PerformOperation();
The following short list of guidelines describes best practices for the design of APIs that need to support timeouts.
DO prefer method parameters as the mechanism for users to provide timeout time.
Method parameters are favored over properties because they make the association between the operation and the timeout much more apparent. The property-based approach might be better if the type is designed to be a component used with visual designers.
DO prefer using TimeSpan to represent timeout time.
Historically, timeouts have been represented by integers. Integer timeouts can be hard to use for the following reasons:
- It is not obvious what the unit of the timeout is.
-
It is difficult to translate units of time into the commonly used millisecond. (How many milliseconds are in 15 minutes?)
Often, a better approach is to use TimeSpan as the timeout type. TimeSpan solves the preceding problems.
class Server { void PerformOperation(TimeSpan timeout){ ... } } var server = new Server(); server.PerformOperation(new TimeSpan(0,15,0));
Integer timeouts are acceptable if:
- The parameter or property name can describe the unit of time used by the operation, for example, if a parameter can be called milliseconds without making an otherwise self-describing API cryptic.
- The most commonly used value is small enough that users won't have to use calculators to determine the value, for example, if the unit is milliseconds and the commonly used timeout is less than 1 second.
DO throw System.TimeoutException when a timeout elapses.
Timeout equal to TimeSpan(0) means that the operation should throw if it cannot complete immediately. If the timeout equals TimeSpan.MaxValue, the operation should wait forever without timing out. Operations are not required to support either of these values, but they should throw an InvalidArgumentException if an unsupported timeout value is specified.
If a timeout expires and the System.TimeoutException is thrown, the server class should cancel the underlying operation.
In the case of an asynchronous operation with a timeout, the callback should be called and an exception thrown when the results of the operation are first accessed.
void OnReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult){ MessageQueue queue = (MessageQueue)source; // the following line will throw if BeginReceive has timed out Message message = queue.EndReceive(asyncResult.AsyncResult); Console.WriteLine("Message: " + (string)message.Body); queue.BeginReceive(new TimeSpan(1,0,0)); }
For more information on timeouts and asynchronous operation, see section 9.2.
DO NOT return error codes to indicate timeout expiration.
Expiration of a timeout means the operation could not complete successfully and thus should be treated and handled as any other runtime error (see Chapter 7).