I am trying to receive Shopify webhooks in Google App Script and can do so, but Shopify requires a response in 5 seconds. If it doesn't get a response "200 OK" it will fire again and again until Shopify deletes your webhook. Not good for me...
I got my webhook deleted with the below code:
function doPost(e) {
//Do stuff (code note included)
return ContentService.createTextOutput('200 OK');
}
I suppose there could be 2 problems
The code is wrong.
The code takes longer than 5 seconds to execute or fails
I wish Shopify would give more info on webhook history so I could see if it's not getting a response. Any insights of how I can solve this problem.
Any ideas on how to solve this?
You state in your question that you do receive the webhook. The usual best practice is to verify the authenticity, and once that passes, you have the data (usually json). At that point, DO NOTHING but save the data for processing later, and return 200 OK as your response to the webhook.
DO NOT process the webhook, and then return 200 OK. The reason is quite simple. If your processing takes time, you kill your response back to Shopify in a timely manner.
A background job to process the data is ideal.
Related
I'm setting up automated tests with AWS Device Farm, and for some reason my upload using the API is just sitting with the Initialized status. It's sending the createUpload() and getting a response with the URL, then sending a request to the URL with the file I want to upload. I'm polling getUpload() every 30 seconds for a change in the status. Here is the main part of my code and the console logs:
https://gist.github.com/asanders-tester/682534925ac314d0805a6dfec547e57f
https://gist.github.com/asanders-tester/40c3e11acd5491aaff7256144f80d8b0
Could anybody provide some insight into what I'm doing wrong? Similar posts here are saying the URL is likely incorrect, but I can't find anything wrong with it.
Cross-posted on AWS Developer Forums: https://forums.aws.amazon.com/thread.jspa?threadID=346232&tstart=0
The upload lifecycle for an upload in AWS Device Farm is that:
It will start in status INITIALIZED
Once your data has been PUT to the presigned URL, it will nearly-immediately enter the status PROCESSING
Shortly-after, the upload will enter a status of SUCCESS or FAILED
It appears that your https request with options is failing to send the data as expected. Can you look into adding an option like "port: 443," to it, as well as printing additional response details when the request is complete?
I have set up the eSignatures API for our app and until recently it has been working perfectly. The part that is now broken is the webhook function. So when a document gets signed by one of our clients, it triggers our webhook cloud function that then updates our database (seems simple?).
The problem is that eSignatures have now updated their timeout to only 8 seconds, which means that my function does not have enough time to run and respond to their servers. It does however still run and update the database correctly, but as it takes longer than 8 seconds, the 200 response never reaches eSignatures and therefore they retry the endpoint every hour (for ~5/6 hours). I have put in a catch so that data is not duplicated when this happens, but ideally we don't want the retries to take place!
My question is basically, is there a way to send a 200 response at the beginning of the function to eSginatures, and then continue with the updates? Or is there another solution to handle this timeout? As if anything does fail in the function, I still want to return a 4xx to eSignatures and in this case we will want the retry?
You can't send a response from your Cloud Functions and then continue executing tasks. When the response is sent, the Function is stopped. See this link and this one
But even if you could, sending a response before ending the tasks that your Cloud Function prevents you from sending a 4XX response if they fail. Hence, eSginatures would never retry.
I don't think you can do much else aside from possibly optimizing your Cloud Function or increasing the eSignatures timeout, which I don't think is possible ATM.
i'm building an angular app that will make about a thousand people to connect simultaneously to book a ticket. I want only "XYZ" of them to access simultaneously at the registration Angular component. The other ones will see a "waiting room" component until it's their turn.
I set up the whole thing like this:
User enters the page.
I make an http call to expressjs server
The server checks if the "connections" collection constains less than XYZ docs
If true, it unlocks the user registation component and with an http post req, it creates a new doc in the db. if false it leaves it hidden and shows up the waitingroom component
When user leaves the page, his doc in "connections" collection gets destroyed with an http delete call.
Fully working.
The problem is now that i want to create a kind of "priority" system, because, going like that, if you just refresh you may be lucky and get access, even if you are soon arrived and there is who is waiting since 1990's. So i introduced a "priority" system. When the user makes the first http call, if user is not allowed, the server creates a timestamp and pushes it into an array.
const timestamps = []
.
.
.
// this below is in http get req
Connessione.countDocuments({},(err,count)=>{
if(count<=nmax){
console.log("Ok")
res.status(200).json({allowed: true})
}
else{
const timestamp = req.params.timestamp;
timestamps.push(timestamp);
console.log("Semo troppi")
res.status(401).json({allowed: false})
}
});
The idea is to listen to db changes, and when there is just XYZ-1 in the db. Make a call to the first timestamp's angular frontend to say him: "Hey there, if you want we're done. You can go" and unlock him the access to registration component.
The problem is that i can't make continuous http requests every second from angular until there's a free place...
Is there any method to send a request at the server, and when server says OK, calls angular and says "Hey dude. You can go!"?
Hope you understood my question. If not ask me in the comments.
Thanks in advance
Even i had trouble with sockets in the beginning so i'll try to explain the concept in a simple way, Whenever you write an API or Endpoint you have a one way connection i.e. you send request to server and it return back some response as shown below.
Event 1:
(Client) -> Request -> (Server)
Event 2:
(Client) <- Response <- (Server)
For API's, without request you cannot get response.
To overcome this issue as of now i can think of two possible ways.
Using Sockets, With sockets you can create a two way connection. Something like this
(Server) <-> data <-> (Client)
It means you can pass data both ways, Client to server and Server to client. So whenever an event occurs(some data is added or updated in database) one can emit or broadcast it to the client and the client can listen to the socket and receive it.
In your case as it's a two connection you can emit the data from angular and
I've attached few links at the bottom. please have a look.
Using XML/AJAX Request, This is not a preferable method, using setInterval you can call the server in every 5 seconds or so and do the operation needed.
setInterval(ajaxCall, 5000); //5000 MS == 5 seconds
function ajaxCall() {
//do your AJAX stuff here
}
Links:
https://socket.io/docs/
https://alligator.io/angular/socket-io/
I have a piece of open source software written in python which uses the bottle web server to display forms in a web browser. The form data are send via "method = post" to the web server. Until now the server process is running on the same (PC) host as the browser, so there is no issue with the internet connection.
Now I have to rewrite this software so that it can be used on mobile devices, with the server somewhere in the internet. The environment in which data entry is to take place will be such that an unstable or lost internet connection is likely. So I have to have provisions for the case that the website containing the form is loaded first (in the office via WLAN, say), then data entry takes place (in the "field") and during data entry, internet connection is lost, so that saving data to the server won't work. In this case it would be great to be able to save the form data locally, in order to send the post-request later on. (Probably it won't be possible to keep the website open all the time until this is possible. The latest when battery goes low, I'd run into problems.)
Probably I'm not the first with this problem, so my question is: is there a "standard" (or well tested) solution for the task to buffer form data on the client side for the case when a post-request is not answered, and send the same request later on? If not, how would you go about to solve this issue? In particular, I see the following (sub-)problems:
How to detect (on the client side) that a post request failed? Probably some kind of timeout mechanism in javascript would have to be employed, but how?
How to save data? My first idea would be to save data to a cookie using javascript. Do I overlook something here?
How to send data back later on?
I'm sufficiently proficient in python to dare this project, but rather new to web technologies, so please excuse if some part of the question is rather stupid. In this case, I'd be grateful to be told so... (... with a hint on how to ask a better question.)
Thanks a lot for any help.
I will try to answer based on (sub-)problems:
How to detect (on the client side) that a post request failed? Probably some kind of timeout mechanism in javascript would have to be employed, but how?
To detect if request failed
Only send status code 200 if you received data and it's saved to backend!
Don't send 200 if there is an error! (use error status code like 5xx or 4xx)
There is a timeout option in jquery to cancel the request if it takes more than given time to complete
When failed, Save data to localStorage
If you are not using jquery, I guess you can do something similar using fetch in vanilla javascript (Click here to know more about fetch)
$.ajax({
timeout: 3000 // sets timeout to 3 seconds
}).done(function () {
console.log("success");
}).fail(function () {
console.log("error");
var _local = localStorage.getItem('data-saved'); //get localStorage data
_local.push({"key": "value"}) // Append JSON based Form data
localStorage.setItem('data-saved', JSON.stringify(_local)); // Update localStorage
});
How to save data? My first idea would be to save data to a cookie using javascript. Do I overlook something here?
Save data using localStorage
In LocalStorage, you can't store JSON however, you can save using JSON.stringify and load back using JSON.parse
// Get data
var get_local_data = JSON.parse(localStorage.getItem('data-saved'));
// Update Data
get_local_data.append({"Name": "value", "age": 10})
// Update localStorage
localStorage.setItem('data-saved', JSON.stringify(get_local_data));
How to send data back later on?
Sending data back using setTimeout method in javascript
Check continuously if there is any data in localStorage's key. If any send an ajax request to back-end!
// Run in each 5 Sec
setTimeout(function () {
// Check if we have any failed data
var get_local_data = JSON.parse(localStorage.getItem('data-saved'));
if(get_local_data.length > 0){
//Make a ajax request
//Update localStorage if success (You need to remove the data from the localStorage),
//Ignored failed case
}
}, 5000);
Using Vue Resource with Vue.js v1
This is also running using vue-router and built with Browserfy.
I have vue-resource working on the whole for post and gets but I have one particular one which occasionally times out or so it seems. I confirm the server is getting the post request and then sending the response back but the webpage sits waiting as if it's missed the response. It seems to happen randomly. If i reload the page and resend then it works.
I've tried to replicate by pausing the server before the sending of the response, wait a bit then continue. In that case it works everytime and webpage continues as expected.
my post functions is as follows (slightly edited to shrink so easier to read)
this.saving = true;
// POST save to the database
this.$http.post('/api/savebr',
{
tNumber: parseInt(this.tNumber),
bNumber: parseInt(this.cNumber)
},
// I added the timeout for testing
{ timeout: 2000 }
).then((response) => {
this.completed.push(parseInt(this.cNumber));
this.saving = false;
}, (response) =>
{
// error callback
console.log(response);
this.saving = false;
alert('Could not save to server. Please try again.');
})
}
In above the timeout works if I pause the server. When the server continues the webpage ignores the response which I guess is correct.
When the webpage randomly misses the response the error callback is never done. It works if I alter response from server to be an error which is expected too.
The timeout option I added recently to see if that makes any odds and also tried with zero setting.
Is it possible to detect the timeout, cancel the current post and send a new one?
If I repeat the post, suddenly both seem to work and so the success code runs twice even though originally the first request seems to be stuck.
Sorry for long post and all pointers gratefully received.