Repository navigation
configStore.get(that.name) returns undefined causes uncaught exception #437
Description
Activity
One possible cause is that the startupUpload()->makeAuthorizedRequest()'s error handler is handleError(), which can call setTimeout(resumeUpload) if the err.code is between > 499 and < 600. And skip the configStore.set(that.name).
One fix is: if handleError() is triggered by the startupUpload(), it should never trigger resumeUpload().
I think I know the cause. The file.js use configure store ('gcloud-node') to keep track of the object upload process. If there are multiple node processes running at the same time, they may overwrite others' config file and cause problems. This effectively prohibit multiple node process running (under one user) to access the GCS at the same time. This is a serious limitation and is not documented anywhere.
I don't understand this design. Why do you need to use persist configure store to keep track every object's upload process? Why cannot you use a simple in-memory-only object to do that? Resumable upload is nice to have, but do you really need to think resumable-upload cross node process restart (at a such high expense)?
I make some changes like below and my stress test that uses multiple node processes is now happy.
diff --git a/node_modules/gcloud/lib/storage/file.js b/node_modules/gcloud/lib/storage/file.js index 7c04437..adfdf35 100644 --- a/node_modules/gcloud/lib/storage/file.js +++ b/node_modules/gcloud/lib/storage/file.js @@ -21,7 +21,14 @@ 'use strict'; var bufferEqual = require('buffer-equal'); -var ConfigStore = require('configstore'); +//var ConfigStore = require('configstore'); +var all = {}; +var configStore = { + all: {}, + get: function(key) { return all[key]; }, + del: function(key) { delete all[key]; }, + set: function(key, value) { all[key] = value; }, +}; var crc = require('fast-crc32c'); var crypto = require('crypto'); var duplexify = require('duplexify'); @@ -766,7 +773,7 @@ File.prototype.startResumableUpload_ = function(stream, metadata) { metadata = metadata || {}; var that = this; - var configStore = new ConfigStore('gcloud-node'); + //var configStore = new ConfigStore('gcloud-node'); var config = configStore.get(that.name); var makeAuthorizedRequest = that.bucket.storage.makeAuthorizedRequest_;
I suppose the real important question here is: Do we really need to support resumable across node process restarts? I'm going to assume yes, so we just likely need better error checking to ensure that the value exists at the time we need to use it, otherwise resumable will not be used.
- addedtype: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.api: storageIssues related to the Cloud Storage API.Issues related to the Cloud Storage API.
on May 14, 2015 - added🚨This issue needs some love.This issue needs some love.triage meI really want to be triaged.I really want to be triaged.
on Apr 6, 2020 - added a commit that references this issue
on Aug 22, 2022 - added a commit that references this issue
on Sep 15, 2022 - added a commit that references this issue
on Oct 12, 2022 - added a commit that references this issue
on Nov 10, 2022 11 remaining items
- added 3 commits that reference this issue
on Jan 27, 2026 - added a commit that references this issue
on Jan 28, 2026 - added a commit that references this issue
on Feb 5, 2026 - added a commit that references this issue
on Feb 17, 2026 - added a commit that references this issue
on Feb 24, 2026 - added a commit that references this issue
on Feb 25, 2026 - added a commit that references this issue
on Mar 5, 2026 - added a commit that references this issue
on Mar 12, 2026 - added 2 commits that reference this issue
on Mar 23, 2026 - added a commit that references this issue
on Mar 27, 2026 - added a commit that references this issue
on May 5, 2026