PouchDB 事务错误
PouchDB transaction error
我希望有人有一些想法。这给我带来了一些实际问题:
Uncaught (in promise) DOMException: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing. {message: "Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.", name: "InvalidStateError", code: 11, stack: "Error: Failed to execute 'transaction' on 'IDBData…ss (http://x.example.com/jav.js:352:56)", INDEX_SIZE_ERR: 1…}n.openTransactionSafely @ pouchdb-3.3.1.min.js:7e._get @ pouchdb-3.3.1.min.js:8(anonymous function) @ pouchdb-3.3.1.min.js:7(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10$.ajax.success @ jav.js:352j @ jquery.js:3094k.fireWith @ jquery.js:3206x @ jquery.js:8259k.cors.a.crossDomain.send.b @ jquery.js:8600
这是我在 PouchDB 中偶尔遇到的错误。它发生在我:
- 获取所有任务
- 一个接一个,将每个任务发送到webservice存储在远程数据库中
- 返回响应后,从 PouchDB 中删除该任务
理由是,只有在网络服务确认后,它才会从移动设备 phone(使用此应用程序的设备)上删除任务。但问题是,由于这个错误,它永远不会删除第一个任务 - 这意味着很多重复项,因为用户会反复同步,想知道为什么它不起作用。
- 继续下一个任务并从第 2 步开始重复。
错误发生在第 3 步左右,在 get
调用中。它似乎是在第一次调用时发生的(即,如果有 3 个任务,则尝试 get
第一个失败)。
我只是想强调 - 这种情况不会一直发生。只是每隔一段时间。通过谷歌搜索,我发现没有很多关于此问题的文档,但它似乎是由某处的竞争条件引起的。
我希望即使问题出在 PouchDB 本身,也许我可以通过某种方式重构我自己的代码,这样这就不会成为一个大问题。
var tasks = [];
myDatabase.allDocs({include_docs: true}).then(function(result) {
totalTasks = result.total_rows;
// Save the tasks
for (var i = 0; i < totalTasks; i++) {
tasks.push(result.rows[i].doc.task)
}
// If there are tasks...
if (tasks.length > 0) {
var syncLogic = function() {
// When the user clicks the sync button; send it off
var postData = {
// Use the username previously submitted
auth: {
username: username,
},
// Empty task because this is a shell - we'll overwrite that when we actually send the task
task: ''
};
// Link to the webservice
var postLink = syncHttpLink;
// Recursive function, because we need to send tasks one at a time
// That way if there's a failure, we'll never have to send the whole lot again
// and risk duplicate tasks.
var sendToWebService = function (count) {
postData.task = tasks[count];
count++;
var jsonStringifyPostData = JSON.stringify(postData);
$.ajax({
url: postLink,
cache: false,
type: 'POST',
timeout: 180000,
data: jsonStringifyPostData,
// When the data has been sent
complete: function () {
// Complete - nothing here currently
},
// When it's successful we'll get a response
success: function (data) {
if (!data.authenticates) {
// Log auth error
// ...
}
if (data.authenticates && data.synced) {
// They logged in, the task has synced. Delete the document from the internal database.
// THIS LINE HERE IS WHERE IT CAUSES THE ERROR:
myDatabase.get(data.id).then(function (doc) {
myDatabase.remove(doc, function(error, response) {
if (error) {
// Log the error
console.log("Database delete error:" + error);
}
else {
console.log("Database record deleted: " + data.id);
// Send the next task
if (count <= (totalTasks - 1)) {
sendToWebService(count);
}
else {
// Finished
exitSync();
}
}
});
});
}
},
// If there's an error...
error: function (xhr, status, error) {
console.log(error);
}
});
};
// First call!
sendToWebService(0);
};
}
});
感谢任何帮助。
嗯,我知道这个问题,但我认为只有在您使用 map/reduce 查询和 destroy()
时才有可能。如果您两者都没有使用(而且看起来是这样),那么这是一个非常有趣的数据点。你能提供一个现场测试用例来重现吗?
另外,您使用的是什么浏览器,PouchDB 是什么版本?
编辑:我使用 Promise.all
重写了您的代码,因此您可以看到它如何为您节省大量编码!与您的问题没有直接关系,但我喜欢教人们 Promises 的乐趣。 :)
myDatabase.allDocs({
include_docs: true
}).then(function(result) {
// post all the data
return PouchDB.utils.Promise.all(result.rows.map(function (row) {
var postData = JSON.stringify({
auth: { username: username },
task: row.doc.task
});
return new PouchDB.utils.Promise(function (resolve, reject) {
$.ajax({
url: postLink,
cache: false,
type: 'POST',
timeout: 180000,
data: postData,
success: function(data) {
if (!data.authenticates) {
reject(new Error('authentication error'));
} else {
// resolve the promise with the doc, so it will appear in the next step
resolve(row.doc);
}
},
error: reject
}));
});
});
}).then(function (docs) {
// remove all the docs
return PouchDB.utils.Promise.all(docs.map(function (doc) {
return myDatabase.remove(doc);
}));
}).catch(function (err) {
// any errors along the way will end up in a single place
console.log(err);
});
我希望有人有一些想法。这给我带来了一些实际问题:
Uncaught (in promise) DOMException: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing. {message: "Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.", name: "InvalidStateError", code: 11, stack: "Error: Failed to execute 'transaction' on 'IDBData…ss (http://x.example.com/jav.js:352:56)", INDEX_SIZE_ERR: 1…}n.openTransactionSafely @ pouchdb-3.3.1.min.js:7e._get @ pouchdb-3.3.1.min.js:8(anonymous function) @ pouchdb-3.3.1.min.js:7(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10(anonymous function) @ pouchdb-3.3.1.min.js:10$.ajax.success @ jav.js:352j @ jquery.js:3094k.fireWith @ jquery.js:3206x @ jquery.js:8259k.cors.a.crossDomain.send.b @ jquery.js:8600
这是我在 PouchDB 中偶尔遇到的错误。它发生在我:
- 获取所有任务
- 一个接一个,将每个任务发送到webservice存储在远程数据库中
- 返回响应后,从 PouchDB 中删除该任务 理由是,只有在网络服务确认后,它才会从移动设备 phone(使用此应用程序的设备)上删除任务。但问题是,由于这个错误,它永远不会删除第一个任务 - 这意味着很多重复项,因为用户会反复同步,想知道为什么它不起作用。
- 继续下一个任务并从第 2 步开始重复。
错误发生在第 3 步左右,在 get
调用中。它似乎是在第一次调用时发生的(即,如果有 3 个任务,则尝试 get
第一个失败)。
我只是想强调 - 这种情况不会一直发生。只是每隔一段时间。通过谷歌搜索,我发现没有很多关于此问题的文档,但它似乎是由某处的竞争条件引起的。
我希望即使问题出在 PouchDB 本身,也许我可以通过某种方式重构我自己的代码,这样这就不会成为一个大问题。
var tasks = [];
myDatabase.allDocs({include_docs: true}).then(function(result) {
totalTasks = result.total_rows;
// Save the tasks
for (var i = 0; i < totalTasks; i++) {
tasks.push(result.rows[i].doc.task)
}
// If there are tasks...
if (tasks.length > 0) {
var syncLogic = function() {
// When the user clicks the sync button; send it off
var postData = {
// Use the username previously submitted
auth: {
username: username,
},
// Empty task because this is a shell - we'll overwrite that when we actually send the task
task: ''
};
// Link to the webservice
var postLink = syncHttpLink;
// Recursive function, because we need to send tasks one at a time
// That way if there's a failure, we'll never have to send the whole lot again
// and risk duplicate tasks.
var sendToWebService = function (count) {
postData.task = tasks[count];
count++;
var jsonStringifyPostData = JSON.stringify(postData);
$.ajax({
url: postLink,
cache: false,
type: 'POST',
timeout: 180000,
data: jsonStringifyPostData,
// When the data has been sent
complete: function () {
// Complete - nothing here currently
},
// When it's successful we'll get a response
success: function (data) {
if (!data.authenticates) {
// Log auth error
// ...
}
if (data.authenticates && data.synced) {
// They logged in, the task has synced. Delete the document from the internal database.
// THIS LINE HERE IS WHERE IT CAUSES THE ERROR:
myDatabase.get(data.id).then(function (doc) {
myDatabase.remove(doc, function(error, response) {
if (error) {
// Log the error
console.log("Database delete error:" + error);
}
else {
console.log("Database record deleted: " + data.id);
// Send the next task
if (count <= (totalTasks - 1)) {
sendToWebService(count);
}
else {
// Finished
exitSync();
}
}
});
});
}
},
// If there's an error...
error: function (xhr, status, error) {
console.log(error);
}
});
};
// First call!
sendToWebService(0);
};
}
});
感谢任何帮助。
嗯,我知道这个问题,但我认为只有在您使用 map/reduce 查询和 destroy()
时才有可能。如果您两者都没有使用(而且看起来是这样),那么这是一个非常有趣的数据点。你能提供一个现场测试用例来重现吗?
另外,您使用的是什么浏览器,PouchDB 是什么版本?
编辑:我使用 Promise.all
重写了您的代码,因此您可以看到它如何为您节省大量编码!与您的问题没有直接关系,但我喜欢教人们 Promises 的乐趣。 :)
myDatabase.allDocs({
include_docs: true
}).then(function(result) {
// post all the data
return PouchDB.utils.Promise.all(result.rows.map(function (row) {
var postData = JSON.stringify({
auth: { username: username },
task: row.doc.task
});
return new PouchDB.utils.Promise(function (resolve, reject) {
$.ajax({
url: postLink,
cache: false,
type: 'POST',
timeout: 180000,
data: postData,
success: function(data) {
if (!data.authenticates) {
reject(new Error('authentication error'));
} else {
// resolve the promise with the doc, so it will appear in the next step
resolve(row.doc);
}
},
error: reject
}));
});
});
}).then(function (docs) {
// remove all the docs
return PouchDB.utils.Promise.all(docs.map(function (doc) {
return myDatabase.remove(doc);
}));
}).catch(function (err) {
// any errors along the way will end up in a single place
console.log(err);
});