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 ...
}
Related
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>)
}
I have an existing async function:
async doJSONGetRequest(getUrl, accessToken) {
return new Promise(function(resolve, reject) {
const reqHeaders = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
};
console.info('url = ' + getUrl);
request.get({
url: getUrl,
headers: reqHeaders,
}, function(err, response) {
if (err) return reject(err);
try {
// console.debug(`response = ${response.body}`);
const parsed = JSON.parse(response.body);
return resolve(parsed);
} catch (err) {
return reject(err);
}
});
});
}
}
I'm trying to test it with Jasmine(v4).
Of course, I don't want this thing to actually make an HTTP request, so I tried rigging up a spy on the 'request' package's 'get' function in the 'beforeAll' section:
describe('RAPIDAPIService', function() {
beforeAll(async function() {
spyOn(request, 'get')
.and
.callFake(async (parameters) => {
if (parameters.url === 'http://localhost/api/getSomething') {
const rsp = {};
rsp.body = 'good stuff';
return rsp;
} else if (parameters.url === 'http://localhost/api/whoops') {
return new Error('401 not found');
} else {
return null;
}
});
});
it('doJSONGetRequest should run successfully', async () => {
expect(api.doJSONGetRequest).toBeDefined();
const res = await api.doJSONGetRequest('http://localhost/api/getSomething', '12345678');
expect(data).toEqual('good stuff');
});
it('doJSONGetRequest should resolve errors properly', async () => {
expect(api.doJSONGetRequest).toBeDefined();
const res = await api.doJSONGetRequest('http://localhost/api/whoops', '12345678');
const expectedError = new Error('401 not found');
expect(res).toEqual(expectedError);
});
Console log statements seem to indicate that I'm actually getting past / returning something from my "await" calls in the "it" tests. But the spies are actually working / detecting that the url's have been called.
(Note that I'm not including here other tests in the same file that do not make asynchronous calls and ARE working... just so you know that there's no problem accessing the actual "api" library and its functions.)
These two tests keep failing with "Error: Timeout - Async function did not complete within 5000ms". And like I said, it seems like they're not returning back to the tests from their calls to the doJSONGetRequest function.
Any thoughts?
Thanks!
I am thinking the issue is the mocking. request.get seems to take two parameters and I am thinking you need to call the 2nd parameter (callback function) once you are done so the resolve can be called.
Try this:
spyOn(request, 'get')
.and
// add callbackFunction as 2nd argument
.callFake((parameters, callbackFunction) => {
if (parameters.url === 'http://localhost/api/getSomething') {
const rsp = {};
rsp.body = 'good stuff';
callbackFunction(null, rsp);
} else if (parameters.url === 'http://localhost/api/whoops') {
callbackFunction({ error: '401 not found' }, {});
} else {
callbackFunction(null, null);
}
});
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;
}
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.
I am trying to call a function located in service class,and if that function returns data,one boolean variable sets true. I have 2 class as bollow:student.ts and service.ts:
// student.ts
public ngOnInit() {
this.config.load().then(() => {
this.service.getRecords().then(
function () { console.log("success getRecord");
this.loading = false; },
function () { console.log("failed getRecord");
this.loading = true; });
});
}
//service.ts
public getRecord(id: number): Promise<T> {
return this.getRecordImpl();
}
private getRecordsImpl(): Promise<T[]> {
let url = this.serviceUrl;
return this.http.get(url, this.getRequestOptionsWithToken())
.toPromise()
.then(res => {
this.records = this.extractData<T[]>(res);
for (var i = 0; i < this.records.length; i++) {
var record = this.records[i];
this.onRecord(record);
}
return this.records;
})
.catch(this.handleError);
}
by the now, records from service returns, but this.service.getRecords(); is undefined. and I can't use
.then
for handling succeed and failure actions.
I know that it is not good idea to make it synchronous. but think that being Asynchronous causes getRecords becomes undefined. What is the solution for handling that. I want it runs sequentially. and if service returns any records , variable initialize to false, otherwise it sets to true.
Many thanks for any help and guide.
I think your aproach is not correct, what is the point to make a promise synchronous ? If you really really want to do this I suggest you to dig in the Synchronous programming with es6 generators but usually the job is done much smother.
From your code I see that you are consuming your Promise by attaching .then() in the service. In this way you should create a new Promise.
private getRecordsImpl(): Promise<T[]> {
let url = this.serviceUrl;
return new Promise((resolve, reject) => {
this.http.get(url, this.getRequestOptionsWithToken())
.toPromise()
.then(res => {
this.records = this.extractData<T[]>(res);
for (var i = 0; i < this.records.length; i++) {
var record = this.records[i];
this.onRecord(record);
}
resolve(this.records);
})
.catch(this.handleError);
})
}
And in your code use:
this.service.getRecords().then(
function (records) { console.log("success getRecord");
this.loading = false; },
function (err) { console.log("failed getRecord");
this.loading = true; });