PouchDB事务错误

时间:2015-05-06 07:11:36

标签: javascript jquery pouchdb

我希望有人有一些想法。这给我带来了一些真正的问题:

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中遇到的错误。它发生在我:

  1. 完成所有任务
  2. 逐个将每个任务发送到Web服务以存储在远程数据库中
  3. 返回响应时,从PouchDB中删除该任务 理由是,只有在网络服务确认后,它才会删除手机上的任务(使用此应用程序)。但问题是,由于这个错误,它永远不会删除第一个任务 - 意味着许多重复,因为用户将反复同步,想知道它为什么不起作用。
  4. 继续执行下一个任务,然后从第2步开始重复。
  5. 错误发生在get电话的第3步附近。它似乎是在第一次调用时发生的(即,如果有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);
                    };
                }
            });
    

    感谢任何帮助。

1 个答案:

答案 0 :(得分:3)

嗯,我知道这个问题,但我认为只有你使用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);
});