I am uploading file chunks to Dropbox and I need to add a simple retry into my loop. So if the first attempt fails, retry another 2 times before giving up.
To give some context. Im uploading a file in chunks to Dropbox. But, I need to allow the script to fail gracefully. Asking the script to repeat the upload 3 times before I kill the upload and give the user an error.
For example (not actual attempt just a concept):
var retries = 3;
jQuery(dropbox.chunks).each(function(index, chunk){
var result = anothingFunction();
if (result == true) {
//continue the loop
}
if (result == false) {
retries--;
if (retries > 0) {
//Retry this iteration
}
if (retries = 0) {
//Kill the entire loop as this upload clearly is not going to happen.
}
}
}
Related
I have one page for uploading a file which will be processed by the server in the background. I then have a second page where it shows only files that have been processed, which can take anything up to 5 seconds.
At the moment the code I have does this
cy.visit('/')
cy.get('.busy-spinner').should('not.exist', { timeout: 10000 })
cy.contains('Submit file').click()
cy.get('[id="requestinputFile"]').attachFile('test-file.txt');
cy.contains('Upload').click()
cy.contains('.notifications', 'Your file has been uploaded', { timeout: 10000 })
cy.wait(5000)
cy.visit('/processed-files')
cy.get('[data-render-row-index="1"] > [data-col-index="1"]').contains(filename)
Sometimes the wait is far too long, sometimes it is not long enough. What I want to do is to go to /processed-files immediately and check if the row with my filename exists.
If it does then continue. Otherwise
Pause for 1 second
Click a specific button (to reload the data on the page)
Wait until .busy-spinner does not exist (the data has been reloaded)
Check if the row exists
If it does then pass, otherwise loop - but for a maximum of 30 seconds.
This pattern will be repeated in many places, what is the best way to achieve this?
Can you just wait on the filename?
cy.contains('[data-render-row-index="1"] > [data-col-index="1"]', filename,
{ timeout: 30_000 }
)
If the reload is needed to get the correct row entry, a repeating function is a possibility
function refreshForData(filename, attempt = 0) {
if (attempt > 30 ) { // 30 seconds with a 1s wait below
throw 'File did not appear'
}
// Synchronous check so as not to fail
const found = Cypress.$(`[data-render-row-index="1"] > [data-col-index="1"]:contains('${filename}')`)
if (!found) {
cy.wait(1_000)
cy.get('Reload button').click()
cy.get('Spinner').should('not.be.visible')
refreshForData(filename, ++attempt)
}
}
refreshForData(filename) // pass in filename, function can be globalized
// maybe also pass in selector?
You can create a recursive function in which you can check the presence of the file name by reloading the page for a maximum of 30 seconds. In case you find the file name you exit the function.
let retry = 0
function isElementVisible() {
if (retry < 15 && Cypress.$('[data-render-row-index="1"] > [data-col-index="1"]'):not(:contains('filename'))) {
//Increment retry
retry++
//wait 2 seconds
cy.wait(2000)
//Reload Page by clicking button
cy.click('button')
//Check busy spinner is first visible and then not visible
cy.get('.busy-spinner').should('be.visible')
cy.get('.busy-spinner').should('not.be.visible')
//Call the recursive function again
isElementVisible()
} else if (retry < 15 && Cypress.$('[data-render-row-index="1"] > [data-col-index="1"]'):contains('filename')) {
//Row found Do something
return
} else {
//It exceeded the required no. of retries and a max of 30 seconds wait
return
}
}
//Trigger the recursive function
isElementVisible()
I am using postman for testing my API.
One of the API which takes some time to process the data I have added a retry logic to try 3 times to check if the end points work fine.
The initial value of retryCount is 3 which is set in the few test before this test where retry is executed.
Below is the code:
let retryCount = pm.environment.get('retryCount');
let responseData = pm.response.json();
console.log(responseData.data.events.length);
console.log(retryCount);
if(responseData.data.events.length == 0 && retryCount > 0)
{
retryCount = retryCount - 1;
console.log(retryCount);
pm.environment.set('retryCount',retryCount);
postman.setNextRequest("GetEvents");
}
else
{
pm.environment.set('data-response',responseData.data);
}
After 3 retries it should stop. however, it goes in the infinite loop. The problem is occurring because the variable is always 3 when the next call happens it should reduce by 1 and eventually become 0.
what could be the reason that above code goes in infinite state.
You might be reseting the value some where in collection scripts or some where elese in your collection. Create a new variable and try, use below method :
pm.variables.get("retryCounter")===undefined ? pm.variables.set('retryCounter',3):null
let responseData = pm.response.json();
console.log(responseData.data.events.length);
retryCount = pm.variables.get("retryCounter");
console.log(retryCount);
if(responseData.data.events.length === 0 && retryCount > 0)
{
retryCount = retryCount - 1;
console.log(retryCount);
pm.variables.set('retryCounter',retryCount)
//this gives this request name , you don't have to hardcode
postman.setNextRequest(pm.info.requestName);
}
else
{
pm.environment.set('data-response',responseData.data);
}
Try this code , here we are using pm.variables.set which creates local variables. As the life time of local variable is the entire collection run and after that it will be destroyed, so for every new collection run the value will be undefined.
we are setting the value to 3 if its undefined . and then sends the request till the value becomes less than 1.
bot.on('message', message => {
if (message.content === 'spam') {
message.channel.send('spam');
while (message.channel.send('spam')) {
if (message.content === 'stop spam') {
return message.channel.send('stopped');
}
}
}
});
im still fairly new to javascript so im not sure if this is even possible the way ive been trying to do it ive looked through w3schools developers.mozilla and even a few questions that are already on here; ive tried using do while, and for loops and ive tried multiple versions of the code i have up there
the ultimate goal is if a user sends the word 'spam' the bot should continuously send the word 'spam' and keep doing so till the bot is turned off or a user sends the words 'stop spam'
Here are some things you should know about the code you're working with:
message.channel.send returns a Promise, so you can't put that in a while loop, because you need to have something that is true or false (a Boolean).
Right now you're trying to check if a message's content is equal to 'stop spam' while you're inside the if-statement checking if the content is equal to 'spam' - So you'll never get inside the inner if-statement.
I would recommend practicing basic javascript a bit more, then moving to Node.js, then coming back to Discord.js - However, it might be cool for you to see a spammer work, so I wrote a some spam code you could use - check this out:
First, create a new file named spamCtrl.js that looks like this (see comments in code for descriptions of what's going on):
let spamming = false;
let spamChannel = undefined;
// spam function repeats until variable spamming is false
function spam() {
return new Promise((resolve, reject) => {
// add check to make sure discord channel exists
if (!spamChannel)
reject('Channel is undefined!');
// send message on spam channel
spamChannel.send('spam')
.then(msg => {
// wait 100 ms until sending next spam message
setTimeout(() => {
// continue spamming if spamming variable is true
if (spamming) {
spam()
.then(resolve) // not entirely necessary, but good practice
.catch(console.log); // log error to console in case one shows up
}
// otherwise, just resolve promise to end this looping
else {
resolve();
}
}, 100)
})
.catch(console.log);
});
}
// public functions that will be used in your index.js file
module.exports = {
// pass in discord.js channel for spam function
setChannel: function(channel) {
spamChannel = channel;
},
// set spam status (true = start spamming, false = stop spamming)
setStatus: function (statusFlag) {
// get current status
let currentStatus = spamming;
// update spamming flag
spamming = statusFlag;
// if spamming should start, and it hasn't started already, call spam()
if (statusFlag && currentStatus != statusFlag) {
spam();
}
},
// not used in my commands, but you may find this useful somewhere
getStatus: function() {
return spamming;
}
};
Next, import that file into your index.js file (Must be in the same directory as your spamCtrl.js file - unless you change the require statement below).
// in index.js file, get controller for spam messages
let spamCtrl = require('./spamCtrl');
Final step: In your index.js file (or wherever you're handling your spam commands) set up your commands (this can be renamed as you like):
// 2 commands together make spamming work :)
case '?SPAM':
spamCtrl.setChannel(message.channel);
spamCtrl.setStatus(true);
break;
case '?STOP-SPAM':
spamCtrl.setStatus(false);
break;
Let me know if you would like any additional explanations on anything, or if you want to see some tweaks here 'n there.
Try using a variable instead. You cannot use message.channel.send('spam') for the while loop.
var spam = false;
if (message.content === 'spam') {
if (message.author.id !== bot.user.id) { // Replace bot with the instance of your bot Client.
spam = true;
} else {
if(spam) {
message.channel.send('spam');
}
}
if (message.content === 'stop spam') {
if(spam) {
message.channel.send('stopped');
}
spam = false;
}
}
I am trying to stream mp3 data from my server to the client side. I am doing this using Ajax. The server sends 50 kilobytes per request. I wrote two functions: one that gets the mp3 data and one that plays them. The first function takes the 50 kilobytes, decodes them and stores the decoded data in an array then it calls itself recursively. The second function starts playing as soon as the first element in the array is filled with data. The problem is that this works for the first 50kilobytes only then it fails. What I want to do is keep my get_buffer function running until the server tells it no more data to send, and keep my play() function playing data until there is no more elements in the array.
Here is my two functions:
function buffer_seg() {
// starts a new request
buff_req = new XMLHttpRequest();
// Request attributes
var method = 'GET';
var url = '/buffer.php?request=buffer&offset=' + offset;
var async = true;
// set attributes
buff_req.open(method, url, async);
buff_req.responseType = 'arraybuffer';
// keeps loading until something is recieved
if (!loaded) {
change_icon();
buffering = true;
}
buff_req.onload = function() {
segment = buff_req.response;
// if the whole file was already buffered
if (segment.byteLength == 4) {
return true;
} else if (segment.byteLength == 3) {
return false;
}
// sets the new offset
if (offset == -1) {
offset = BUFFER_SIZE;
} else {
offset += BUFFER_SIZE;
}
//decodes mp3 data and adds it to the array
audioContext.decodeAudioData(segment, function(decoded) {
buffer.push(decoded);
debugger;
if (index == 0) {
play();
}
});
}
buff_req.send();
buff_seg();
}
Second function:
function play() {
// checks if the end of buffer has been reached
if (index == buffer.length) {
loaded = false;
change_icon();
if (buffer_seg == false) {
stop();
change_icon();
return false;
}
}
loaded = true;
change_icon();
// new buffer source
var src = audioContext.createBufferSource();
src.buffer = buffer[index++];
// connects
src.connect(audioContext.destination);
src.start(time);
time += src.buffer.duration;
src.onended = function() {
src.disconnect(audioContext.destination);
play();
}
}
The recursive call to buffer_seg is in the main body of buffer_seg, not in the callback, so it happens immediately - not, as you seem to intend, after a response is received. Second, this also means that the recursive call is unconditional when it should be based on whether the previous response indicated more data would be available. If this isn't just crashing your browser, I'm not sure why. It also means that chunks of streamed audio could be pushed into the buffer out of order.
So to start I'd look at moving the recursive call to the end of the onload handler, after the check for end of stream.
In the 2nd function, what do you intend if (buffer_seg == false) to do? This condition will never be met. Are you thinking this is a way to see the last return value from buffer_seg? That's not how it works. Perhaps you should have a variable that both functions can see, which buffer_seg can set and play can test, or something like that.
Hi I have a loop in JSON to retry connection 3x before firing an error however sometimes I have 3-4 JSON requests and all of them can trough an errors so I have 3 alerts in my phonegap app.
EG.
function showJSONerror(xhr, status) {
if (xhr.status === 0 && localStorage["TmpAlertShow"] !== true) {
navigator.notification.confirm('Connection error.\n Verify your network connection and try again.', confirmAction, 'Woops...','Try Again, Close');
localStorage["TmpAlertShow"] = true;
function confirmAction(button) {
if (button == 1) { localStorage["TmpAlertShow"] = false; showPage(localStorage["TmpWebView"]) }
if (button == 2) { localStorage["TmpAlertShow"] = false; return false; }
}
}
I'm trying to find the way to close previous alert via JS or record the sate if the alert is already fired and not closed (prevent to display a multiple alerts)
Thanks
You could try something like setting a global variable that is the count of requests currently running and then in your error function, say if the count is greater than 0 store the result in a global array and if not then process the errors for display.
Example:
var callsRunning = 0;
var callStatuses = [];
When running a call add:
callsRunning++;
When a call is done:
callsRunning--;
in your error function:
if(callsRunning > 0) {
callStatuses.push(/*whatever you want to collect*/);
}
else {
/*compile statuses for display of error*/
}
i've had a similar problem before
I used to resolve it http://underscorejs.org/#after
maybe give this a shot?