Skip to content

Commit 075e586

Browse files
authored
Add ability to set a timeout on Functions. (#2329)
Changes the default timeout for FirebaseFunctions to 70s and adds an API to override that timeout on a per-function basis.
1 parent 2a10f5b commit 075e586

File tree

9 files changed

+63
-4
lines changed

9 files changed

+63
-4
lines changed

Functions/Backend/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,9 @@ exports.httpErrorTest = functions.https.onRequest((request, response) => {
107107
// Send an http error with no body.
108108
response.status(400).send();
109109
});
110+
111+
exports.timeoutTest = functions.https.onRequest((request, response) => {
112+
// Wait for longer than 500ms.
113+
setTimeout(() => response.send({data: true}), 500);
114+
});
115+

Functions/Backend/start.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ FUNCTIONS_BIN="./node_modules/.bin/functions"
4747
"${FUNCTIONS_BIN}" deploy unknownErrorTest --trigger-http
4848
"${FUNCTIONS_BIN}" deploy explicitErrorTest --trigger-http
4949
"${FUNCTIONS_BIN}" deploy httpErrorTest --trigger-http
50+
"${FUNCTIONS_BIN}" deploy timeoutTest --trigger-http
5051

5152
# Wait for the user to tell us to stop the server.
5253
echo "Functions emulator now running in ${TEMP_DIR}."

Functions/Example/IntegrationTests/FIRIntegrationTests.m

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,19 @@ - (void)testHttpError {
196196
[self waitForExpectations:@[ expectation ] timeout:10];
197197
}
198198

199+
- (void)testTimeout {
200+
XCTestExpectation *expectation = [[XCTestExpectation alloc] init];
201+
FIRHTTPSCallable *function = [_functions HTTPSCallableWithName:@"timeoutTest"];
202+
function.timeoutInterval = 0.05;
203+
[function
204+
callWithCompletion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) {
205+
XCTAssertNotNil(error);
206+
XCTAssertEqual(FIRFunctionsErrorCodeDeadlineExceeded, error.code);
207+
XCTAssertEqualObjects(@"DEADLINE EXCEEDED", error.userInfo[NSLocalizedDescriptionKey]);
208+
XCTAssertNil(error.userInfo[FIRFunctionsErrorDetailsKey]);
209+
[expectation fulfill];
210+
}];
211+
[self waitForExpectations:@[ expectation ] timeout:10];
212+
}
213+
199214
@end

Functions/FirebaseFunctions/FIRFunctions+Internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
3131
*/
3232
- (void)callFunction:(NSString *)name
3333
withObject:(nullable id)data
34+
timeout:(NSTimeInterval)timeout
3435
completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
3536
NSError *_Nullable error))completion;
3637

Functions/FirebaseFunctions/FIRFunctions.m

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ - (NSString *)URLWithName:(NSString *)name {
159159

160160
- (void)callFunction:(NSString *)name
161161
withObject:(nullable id)data
162+
timeout:(NSTimeInterval)timeout
162163
completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
163164
NSError *_Nullable error))completion {
164165
[_contextProvider getContext:^(FUNContext *_Nullable context, NSError *_Nullable error) {
@@ -168,16 +169,25 @@ - (void)callFunction:(NSString *)name
168169
}
169170
return;
170171
}
171-
return [self callFunction:name withObject:data context:context completion:completion];
172+
return [self callFunction:name
173+
withObject:data
174+
timeout:timeout
175+
context:context
176+
completion:completion];
172177
}];
173178
}
174179

175180
- (void)callFunction:(NSString *)name
176181
withObject:(nullable id)data
182+
timeout:(NSTimeInterval)timeout
177183
context:(FUNContext *)context
178184
completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
179185
NSError *_Nullable error))completion {
180-
GTMSessionFetcher *fetcher = [_fetcherService fetcherWithURLString:[self URLWithName:name]];
186+
NSURL *url = [NSURL URLWithString:[self URLWithName:name]];
187+
NSURLRequest *request = [NSURLRequest requestWithURL:url
188+
cachePolicy:NSURLRequestUseProtocolCachePolicy
189+
timeoutInterval:timeout];
190+
GTMSessionFetcher *fetcher = [_fetcherService fetcherWithRequest:request];
181191

182192
NSMutableDictionary *body = [NSMutableDictionary dictionary];
183193
// Encode the data in the body.
@@ -225,6 +235,11 @@ - (void)callFunction:(NSString *)name
225235
if ([error.domain isEqualToString:kGTMSessionFetcherStatusDomain]) {
226236
error = FUNErrorForResponse(error.code, data, serializer);
227237
}
238+
if ([error.domain isEqualToString:NSURLErrorDomain]) {
239+
if (error.code == NSURLErrorTimedOut) {
240+
error = FUNErrorForCode(FIRFunctionsErrorCodeDeadlineExceeded);
241+
}
242+
}
228243
} else {
229244
// If there wasn't an HTTP error, see if there was an error in the body.
230245
error = FUNErrorForResponse(200, data, serializer);

Functions/FirebaseFunctions/FIRHTTPSCallable.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ - (instancetype)initWithFunctions:(FIRFunctions *)functions name:(NSString *)nam
5151
}
5252
_name = [name copy];
5353
_functions = functions;
54+
_timeoutInterval = 70.0;
5455
}
5556
return self;
5657
}
@@ -63,7 +64,10 @@ - (void)callWithCompletion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
6364
- (void)callWithObject:(nullable id)data
6465
completion:(void (^)(FIRHTTPSCallableResult *_Nullable result,
6566
NSError *_Nullable error))completion {
66-
[_functions callFunction:_name withObject:data completion:completion];
67+
[_functions callFunction:_name
68+
withObject:data
69+
timeout:self.timeoutInterval
70+
completion:completion];
6771
}
6872

6973
@end

Functions/FirebaseFunctions/FUNError.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,19 @@
1414
// limitations under the License.
1515

1616
#import <Foundation/Foundation.h>
17+
#import "FIRError.h"
1718

1819
@class FUNSerializer;
1920

2021
NS_ASSUME_NONNULL_BEGIN
2122

23+
/**
24+
* Takes an error code and returns a corresponding NSError.
25+
* @param code The eror code.
26+
* @return The corresponding NSError.
27+
*/
28+
NSError *_Nullable FUNErrorForCode(FIRFunctionsErrorCode code);
29+
2230
/**
2331
* Takes an HTTP status code and optional body and returns a corresponding NSError.
2432
* If an explicit error is encoded in the JSON body, it will be used.

Functions/FirebaseFunctions/FUNError.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
// limitations under the License.
1515

1616
#import "FUNError.h"
17-
#import "FIRError.h"
1817

1918
#import "FUNSerializer.h"
2019

@@ -141,6 +140,11 @@ FIRFunctionsErrorCode FIRFunctionsErrorCodeForName(NSString *name) {
141140
return @"UNKNOWN";
142141
}
143142

143+
NSError *_Nullable FUNErrorForCode(FIRFunctionsErrorCode code) {
144+
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : FUNDescriptionForErrorCode(code)};
145+
return [NSError errorWithDomain:FIRFunctionsErrorDomain code:code userInfo:userInfo];
146+
}
147+
144148
NSError *_Nullable FUNErrorForResponse(NSInteger status,
145149
NSData *_Nullable body,
146150
FUNSerializer *serializer) {

Functions/FirebaseFunctions/Public/FIRHTTPSCallable.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ NS_SWIFT_NAME(HTTPSCallable)
8989
NS_SWIFT_NAME(call(_:completion:));
9090
// clang-format on
9191

92+
/**
93+
* The timeout to use when calling the function. Defaults to 60 seconds.
94+
*/
95+
@property(nonatomic, assign) NSTimeInterval timeoutInterval;
96+
9297
@end
9398

9499
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)