InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing with ios safari
Asked Answered
E

2

13

I have issue since Aug 2020 and i still don't know how to reproduce, I am using dfahlander/Dexie.js to use browser indexedDB.

This is sample of how i am using dexie:-

import db from "./db";
import { useState, useEffect } from "react";
import axios from "axios";
import {   useParams } from "react-router-dom";

export default function App() {
  const params =   useParams();
  const [storedRead, setStoredRead] = useState();
  const [data,setData] = useState();

  useEffect(() => {
          db.reads
            .get({ hash: params.id })
            .then((data) => {
              setStoredRead(data);
              readRequest(data ? data.token : "");
            })
            .catch((e) => {
              //Here i am getting error with ios users, not all of them
              // InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.   
            });
 
  }, []);

  const readRequest = (token) => {
    axios
      .post(`${process.env.REACT_APP_API_URL}khatma/read`, {
        khatma: params.id,
        part: params.part,
        section: params.section,
        token: token, 
      })
      .then((res) => {
        if (res.data.token) {
          db.reads
            .put(
              {
                hash: params.id,
                token: res.data.token,
                ss: "",
                sa: "",
              },
              params.id
            )
            .then((event) => {
              db.reads.get({ hash: params.id }).then((read) => {
                setStoredRead(read);
                setData(res.data);
              });
              
            })
            .catch((e) => {
             
            });
  
        } else {
          setData(res.data);
  
          db.reads.get({ hash: params.id }).then((read) => {
            setStoredRead(read);
            setData(res.data);
          
          });
          
        }
    
      })
      .catch((error) => {
      
      });
  };

  return (
    <div className="App">
     
    </div>
  );
}

db.js file :-

import Dexie from "dexie";
const db = new Dexie("khatmaDB");
db.version(2).stores({
  reads: "hash,token,sa,ss",
  khatmas: "hash,token"
});

console.log("dexie version", db.verno);

export default db;

Since Aug 2020 i have about 25K log record with the following error:-

InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.

Its happens only with user-agent = ios safari with different ios versions (11 to 14) Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1

If we asked the user to clear his browser website data (iPhone setting > safari > advanced > website data > delete website data). Issue get resolved even-though they have available iPhone storage space more than 20GB, but we cannot ask each user to delete their websites data.

Any idea what is the causes of this issue ?

Excerpt answered 11/2, 2021 at 13:38 Comment(0)
A
0

As a guess, dexie probably closes the database connection at the end of a promise chain. You have nested promises, but you are not chaining them properly, so as a result, your .then(...) call is trying to make an additional request but the library has already decided to call db.close() internally. Once some code calls db.close, future requests or transactions fail with a similar error message.

To fix this, you need to make sure you properly chain your promises.

In addition, you have to be careful about interleaving different kinds of promises, as the transaction will timeout and then you will get a different error. However, that is not what you asked about here. So here, it has to be because you are performing a request on a transaction after the transaction's db instance has started to close. And without knowing the internals of the library, that is probably because you are not preventing the call to db.close from happening, because you are not chaining your promises.

Explaining how to properly chain is a lengthy answer, but briefly, the relevant bit is that you need to do this:

myPromise()
  .then(thing => {
    // the key insight, you are missing the return here
    return anotherPromise();
  }).then(anotherThing => {
    // now this runs in a way that is similar to anotherPromise.then(...)
  })

Once you return a promise from the then callback, that serializes (puts into order) the chain of statements such that you will prolong the promise chain.

What you are doing, it looks like, is this:

  .then(thing => {
    // this is not returned, so then() resolves to undefined immediately
    anotherPromise();
  }).then(anotherThing => {
    // this runs at the same time as anotherPromise() without waiting for it
  })

Because of the immediate resolve in the nested promise, the idb library thinks you are done, so it calls db.close() internally, but then you do more stuff with that connection but it is already closing so you get an error.

Arron answered 18/7 at 6:12 Comment(0)
A
-4

hmmm.... i did some RND on this for this issue you just create the global error handling service you can put check for this issue and just reload the app it will work

if(err.message.search('transaction' on 'IDBDatabase')>-1) { window.location.reload() `}

Almanza answered 3/11, 2021 at 7:20 Comment(1)
good tip - but not work - I have to close whole " mobile app safari "Futrell

© 2022 - 2024 — McMap. All rights reserved.