Cloud Function with Multiple Triggers - Scheduled and onCall - firebase

I have a cloud function that I would like to run whenever a user performs a set of actions on the web app AND daily at a specified time. In the interest of not duplicating code and future features/bug fixes, I'd like to run both from one function/file.
Any suggestions/references on this flow would be greatly appreciated!

You can write your business logic in one function, that you call from the two Cloud Functions. Something along the following lines, with an asynchronous business logic and the use of async/await:
exports.myFunctionCalledFromTheApp = functions.https.onCall(async (data, context) => {
try {
const result = await asyncBusinessLogic();
return { result: result }
} catch (error) {
// ...
}
});
exports.myFunctionCalledByScheduler = functions.pubsub.schedule('every 24 hours').onRun(async (context) => {
try {
await asyncBusinessLogic();
return null;
} catch (error) {
// ...
return null;
}
});
async function asyncBusinessLogic() {
const result = await anAsynchronousJob();
return result;
}

Related

Get async results within .map function

I'm trying to get photos in map function from Nest.js server. This is slider component. I give an array of slides as input and show on within a map.
The thing is, I need to get real file from server (by res.sendFile..) while doing .map.
I searched and tried a few variants, this is the last, but still get errors.
what do I do wrong? Please, help
const Slider = async ({videos}) => {
async function getImageHandler(fileName) {
return getImageFromNestServer(fileName).then(async (response) => {
const fileType = await FileType.fromBuffer(response.data);
return `data:${fileType.mime};base64, ${ArrayBufferConverter.encode(response.data)}`;
})
}
let realImg = await Promise.all(
videos.map(async video => {
try {
video.fetchItem = await getImageHandler(video.content_preview_photo.filename)
return video;
} catch(err) {
throw err;
}
}
)
)
return (<MySlide>...</MySlide>)
}

How to unit-test timeout in Flutter?

I have a facade function that reloads the current firebase user and returns it. The thing is that the user reloading part has a timeout and it needs to be tested.
Function:
Future<Option<User>> getSignedInUser() async {
// Reload currentUser if possible
// it mustn't throw [TimeoutException] for whole function,
// this is what this try/catch does
try {
await reloadCurrentUser().timeout(const Duration(seconds: 20));
} catch (e) {
log(e.toString(), name: TAG);
}
return optionOf(_auth.currentUser);
}
reloadCurrentUser() function:
Future<Either<AuthFailure, Unit>> reloadCurrentUser() async {
try {
await _auth.currentUser?.reload();
return right(unit);
} catch (e) {
log(e.toString(), name: TAG);
return left(const AuthFailure.userReloadingError());
}
}
The question is how to test reloadCurrentUser() timeout? I'm trying to throw a TimeoutException when this function is called, but then it throws an error for the whole test.
Current Test function:
test(
'Reaches timeout when reloading currentUser, '
'throws TimeoutException, but function continues '
'and returns optionOf currentUser', () async {
reset(fakeFirebaseAuth);
reset(fakeFacebookAuth);
reset(fakeGoogleSignIn);
final currentUser = FakeUser();
// It says that currentUser exists and *IS* authenticated
when(() => fakeFirebaseAuth.currentUser).thenReturn(currentUser);
when(() => firebaseAuthFacade.reloadCurrentUser())
.thenThrow(TimeoutException('timeout', const Duration(seconds: 20)));
final result = await firebaseAuthFacade.getSignedInUser();
expect(result, isA<Some<User>>());
});
Maybe it's better to remove timeout and use some connectivity package to ensure that the user has a network connection and only then reload the current user?
For testing I'm using mocktail package.
You can use the fake_async package.
Here's a simple example from their docs that you can modify for your use case:
import 'dart:async';
import 'package:fake_async/fake_async.dart';
import 'package:test/test.dart';
void main() {
test("Future.timeout() throws an error once the timeout is up", () {
// Any code run within [fakeAsync] is run within the context of the
// [FakeAsync] object passed to the callback.
fakeAsync((async) {
// All asynchronous features that rely on timing are automatically
// controlled by [fakeAsync].
expect(Completer().future.timeout(Duration(seconds: 5)),
throwsA(isA<TimeoutException>()));
// This will cause the timeout above to fire immediately, without waiting
// 5 seconds of real time.
async.elapse(Duration(seconds: 5));
});
});
}

Firebase schedule a function with multiple crontabs

I want my function to run once a day, but twice on weekends. How do I do that with Firebase?
My crontabs:
0 16 * * *
0 22 * * 6,0
From what I know, my only chooce is to create another instance of the same function with a different crontab. Is there a better way?
Thanks
From what I know, my only choice is to create another instance of the
same function with a different crontab. Is there a better way?
Yes, this is the only solution. However you can put the "main" code in one function, as follows:
exports.scheduledFunction1 = functions.pubsub.schedule('...').onRun(async (context) => {
try {
await mainFunction();
return null;
} catch (error) {
console.log(error);
return null;
}
});
exports.scheduledFunction2 = functions.pubsub.schedule('...').onRun(async (context) => {
try {
await mainFunction();
return null;
} catch (error) {
console.log(error);
return null;
}
});
async function mainFunction() {
//await ...
}

Parse Cloud Code response is null after calling a function with callback

I have a cloud code from which I call an external function.
The cloud code response is null but the console displays the response
my cloud code ;
Parse.Cloud.define("testccadd", async request => {
try {
var ccaddrequest = {
conversationId: '123456789',
email: 'email#email.com',
};
externalFunction (ccaddrequest, function (err, result) {
console.log(result);
return result;
}) ;
} catch (e) {
console.log("Error");
}
});
console.log (result); shows the values from the external function, but the return result; returns null
how can I get the external function response as response of my cloud code function ?
The problem is that your externalFunction uses a callback to return its result. That is an asynchronous event, meaning that it happens after your cloud functions has been processed.
The cloud function will execute var ccaddrequest... and then call externalFunction but it won't "wait" for externalFunction to call the callback function if it contains asynchronous commands.
So you need to wrap the externalFunction in a Promise (see how to promisify callbacks) and then await the result of it.
Plus you need to return the result of the Promise, so in your code you need to add
Parse.Cloud.define("testccadd", async request => {
try {
var ccaddrequest = {
conversationId: '123456789',
email: 'email#email.com',
};
var result = await externalFunctionPromise(...);
return result;
} catch (e) {
console.log("Error");
}
});

What's the difference between Future.error and throw in dart Future?

I'd like to understand when to use throw and return Future.error in async functions. Are there any underlying differences that we should take in consideration when choosing one or the other?
I did a small test:
Future testFuture() async {
return Future.error('error from future');
}
void testThrow() {
throw('error from throw');
}
Future testFutureThrow() async {
throw('error from future throw');
}
main() async {
print('will run test');
try{
await testFuture();
}
catch(e){
print(e);
}
try{
testThrow();
}
catch(e){
print(e);
}
try{
await testFutureThrow();
}
catch(e){
print(e);
}
testFuture().catchError((e) => print(e));
testFutureThrow().catchError((e) => print(e));
print('did run test');
}
They both seem to work in the same way. This is the output:
will run test
error from future
error from throw
error from future throw
did run test
error from future
error from future throw
What we can see from this test is that, from the point of view of the caller, when call the function using try/catch the code runs synchronous and if we Future.catchError it's asynchronous. But from the point of view of the function flow it appears to be the same.
NOTE: I had this initially as a response to a question. But then I realised that I was not answering but instead doing a question.
async and await are a language extension/syntactic sugar to simplify working with asynchronous code by restoring a synchronous fashion.
Both abstract away working with Futures directly, making this code analogous:
// On the callee's side
Future<String> calleeAsync() async {
return "from async callee";
}
Future<String> calleeSync() {
return Future.value("from sync callee");
}
// On the caller's side
Future<void> callerAsync() async {
print("got ${await calleeAsync()}");
print("got ${await calleeSync()}");
}
void callerSync() {
calleeAsync()
.then((v) => print("got3 $v"))
.then((_) => calleeSync())
.then((v) => print("got4 $v"));
}
(while in callerSync the second then()'s callback could be merged with the first's, and the third then() could also be attached directly to calleeSync() because of monad-like associativity)
In the same manner, these functions are equivalent:
// On the callee's side
Future<void> calleeAsync() async {
throw "error from async";
}
Future<void> calleeSync() {
return Future.error("error from sync");
}
// On the caller's side
Future<void> callerAsync() async {
try {
await calleeAsync();
} catch (e) {
print("caught $e");
}
try {
await calleeSync();
} catch (e) {
print("caught $e");
}
}
void callerSync() {
calleeAsync()
.catchError((e) => print("caught $e"))
.then((_) => calleeSync())
.catchError((e) => print("caught $e"));
}
In summary, there is no practical difference. return Future.error(…) simply doesn't make use of the extensions an async function provides, thus it's more like mixing two flavours of asynchronous code.
My experience is that if you want to use myFunc().then(processValue).catchError(handleError); you should return Future.error but not throw it.

Resources