My html form uploads data to a spreadsheet with a Google script. I use the following function to prevent a conflict, since many users are accessing the web app page:
function lockservice() {
var lock = LockService.getScriptLock();
lock.waitLock(30000);
lock.releaseLock();
}
I have another script to retrieve the data (separate script), that also has many users accessing it. So do I need getscriptlock for that also?
In another words, is there a conflict between users occuring when getting the data or only when uploading it? or maybe in both cases.
If you are writing data to the spreadsheet with:
sheet.appendRow(array);
then you don't need Lock Service to write data. If you are using:
sheet.getRange().setValues(array_2_D);
Then you do need Lock Service.
So, appendRow() is "atomic" and setValues() is not. Atomic meaning that each operation runs completely independent from each other.
https://developers.google.com/apps-script/reference/spreadsheet/sheet?hl=en#appendRow(Object)
Getting values should use Lock Service if you have concurrent users. There is also a quota limit for concurrent users. The limit for "Simultaneous Executions" is 30, (at the time of this post)
https://developers.google.com/apps-script/guides/services/quotas#current_limitations
I have actually have the same understanding but:
I have a script where Lock Service is used and the locked section also includes a appendRow() operation to the sheet.
The script allows up to 30 concurrent executions.
Despite knowing that appendRow()is stated to be atomic, I now experience that appendRow() actually may overwrite the last used row on a sheet!
I never experienced this behavior without making use of the Lock Service.
Anybody else observed this unexpected behavior?
In the linked screenshot you see the new Date() value of the previous record being replaced instead of an entire new row being appended below.
Any thoughts & suggestions to overcome this behavior are highly appreciated.
Screenshot: appendRow() replaces last row of sheet:
Related
I have one backend function to append new rows to a Google Sheet and a lock service is used to prevent the conflicts of multiple users.
sh.appendRow(record);
Another backend function is to delete rows from the same sheet and a lock service is used as well.
sh.deleteRow(posIndex+2)
While I have concern that one user is appending a row at the same time as another user is deleting a row, will it cause any trouble? Since the lock service is used independently in these two functions, they will not lock each other.
The Lock Service has three scopes,
User
Document
Script
Using the the document scope is very likely to be the best option. For this use getDocumentLock().
Related
How to understand LockService and implement it correctly?
How to check if a function in Google App Script is already being executed by another user?
I developed numbers of custom scripts in a project which supposed to run over lastrow of data in response sheet linked to a gform upon submission of that gform. When tested, it took around 45 seconds to finish all the custom scripts.
Now here is where I get worried and I'm looking for a firm answer which I still cannot find from google search. Within that 45 seconds of processing, other gform users can submit the form and I'm thinking every latest submission will be taken as lastrow of data in the response sheet.
So, since my custom scripts will always refer and/or getValue(s) on the lastrow of response sheet, will that makes some of my scripts will jump on to the latest row of data before it finishes the previous one just because the latest submission is before the 45 seconds is finished? I'm so worried that if it is yes, that definitely will make the output become a disaster.
Add Info. I have one main function that calls other subfunctions chronologically and some subsubfunction(s) been called from that subfunction. Please refer below:-
function MAINFUNCTION(){
var sheet=SpreadsheetApp.getActiveSheet();
MYfunctionA();
MYfunctionB();
MYfunctionC();
}
MYfunctionB(){
//something done here..
mysubfunctionB();
return
}
MYfunctionA(){
//something done here..
return
}
MYfunctionC(){
//something done here..
return
}
So, if LockService is the solution, must it be applied to every subfunction? Another thing, what will happen if there's a google service/server error during that locktime? will it release the lock and proceed with the next record?
Or will it auto-retry? Because during testing, sometimes I got this service/server error prompted and usually I just rerun it back, but I wonder what will happen if this project is launched and used by many users almost concurrently?
I am familiar with the Lock Service but that is only for locking scripts.
I have some code that will "process" a large Google Sheet. My script needs to re-order the rows. I need/want to make it so while the script is running nobody else can change the order. However, I still need another script to be able to append rows.
We use a Google Form for our team's intake. It appends rows to a sheet. I have an hourly job that will go through all the rows/records and "process them". I have a column that stores the last time a record/row was "processed". I want to sort on that column such that the "oldest" records are on top and then start processing from the top down. If the script fails or times out then the next iteration will just start over...
I know I could use getValues or getDisplayValues to get an array and then write the array back but I worry what would happen if someone sorted the rows as it would muck things up when writing the array back.
Is there some way to accomplish my goal? I want to be able to process the records, and maintain row order to avoid breaking my processing.
The way to block a spreadsheet "completely" is by changing the spreadsheet sharing settings. Remove all editors or change them to viewers, once your script finish, change them back as editors. In a extreme case, usa a second account to act as the owner of the critical files / spreadsheets and only use it for this purpose,so you could block your regular account for doing changes to the spreadsheet.
NOTE: A Google Form editResponseUrl could be used to edit the linked spreadsheet.
I'm facing a similar situation but I took a different approach, I'm using an index/key column (you could use the timestamp column) and using the index/key to save each edited row to the right position, then write the whole resulting array in a single operation (by using setValues()). In my case this is simple because I only require values, I'm not worried about notes, data validation, conditional formatting, comments, etc. and there isn't a Google Form linked to my spreadsheet.
Related
Google Spreadsheet -- get sharing permissions by script
Any way to share google docs programmatically?
I have multiple scripts that I want to run on data in my spreadsheet. Some of the data is populated by random number function.. so they change every time the spreadsheet is updated/edited.
It seems that my scripts update the spreadsheet even if it doesn't explicitly edit any cells. This causes all of the data to change mid-script and mess things up.
Is there any way to stop the spreadsheet from updating while a script is running?
No, I don't think so. You'll need to come up with a way of structuring the retrieval and updating of data, and the timing of the flow of events. You could check for certain conditions, and halt the script if need be. You could set key cell values from a script, rather than a function in the cell.
This question already has answers here:
build real time dashboard using google apps script
(3 answers)
Closed 2 years ago.
I'm developing a Web App using google apps script and a spreadsheet as storage.
Basically, an HTML showing some tables for the different tabs.
From my app, users can add new tasks, edit tasks, and mark tasks as completed.
Since there are many users using the app, the data showed on each client will get outdated very fast.
I would like to update the app with new records and changes to the existing ones as soon as possible.
I thought in logging the last edit tab+row in a cell and pull that data from the server every minute, but, what if many entries are added/edited during that minute?
I think WebSocket is not possible. Any other idea?
I'm using JQuery client-side.
To help avoid conflicts, give every task a unique ID. Something like creation time + random string. That way you can look it up in the spreadsheet. Also, I think the Lock Service can prevent concurrent edits temporarily to avoid conflicts:
https://developers.google.com/apps-script/reference/lock/
To check for updates, try polling the last edit time of the spreadsheet. If it's greater than the previous poll, fetch updates.
https://developers.google.com/apps-script/reference/drive/file#getLastUpdated()
No other way besides polling. You can't have sockets or callbacks from HTML service. You could poll frequently but that may run you out of quotas.
If you really want to poll and avoid quotas you can log the last edit on a published public spreadsheet and read it with ajax from the client, however published spreadsheets update every minute only.
You could try something like this:
var lock = LockService.getPublicLock();
var success = lock.tryLock(10000);
if (success) {
// check your spreadsheet for lastUpdated or PropertiesService.getScriptProperties();
}
} else {
// do something else (try it again or error msg)
}
lock.releaseLock();
I have found that it works well on my app and I have around 1000 users.