PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Проблеми с връзката с SQLAlchemy и множество процеси

Цитирайки "Как да използвам двигатели/връзки/сесии с многопроцесорна обработка на Python или os.fork()?" с допълнителен акцент:

Обектът SQLAlchemy Engine се отнася до пул за връзки от съществуващи връзки към база данни. Така че, когато този обект се репликира в дъщерен процес, целта е да се гарантира, че не се пренасят връзки към базата данни .

и

Въпреки това, в случай на споделена сесия или връзка с активна транзакция, няма автоматично решение за това; едно приложение трябва да гарантира, че нов дъщерен процес инициира само нови обекти и транзакции за връзка, както и обекти ORM Session.

Проблемът произтича от разклонения дъщерен процес, наследяващ глобалната сесия на живо , който държи Връзка . Когато target извиква init , той презаписва глобалните препратки към engine и сесия , като по този начин намалява техните refcounts до 0 в детето, принуждавайки ги да финализират. Ако например по един или друг начин създадете друга препратка към наследената сесия в детето, вие предотвратявате изчистването й – но не правете това. След main се присъедини и се връща към обичайния си начин, той се опитва да използва сега потенциално финализираната – или по друг начин несинхронизирана – връзка. Не съм сигурен защо това причинява грешка само след известно количество повторения.

Единственият начин да се справите с тази ситуация, като използвате глобални по начина, по който го правите, е да

  1. Затваряне на всички сесии
  2. Обадете се на engine.dispose()

преди разклоняване. Това ще предотврати изтичане на връзки към детето. Например:

def main():
    global session
    init()
    try:
        dummy = Dummy(value=1)
        session.add(dummy)
        session.commit()
        dummy_id = dummy.id
        # Return the Connection to the pool
        session.close()
        # Dispose of it!
        engine.dispose()
        # ...or call your cleanup() function, which does the same
        p = multiprocessing.Process(target=target, args=(dummy_id,))
        p.start()
        p.join()
        # Start a new session
        session = Session()
        dummy = session.query(Dummy).get(dummy_id)
        assert dummy.value == 2
    finally:
        cleanup()

Вторият ви пример не задейства финализиране в детето и така изглежда само работи, въпреки че може да е също толкова счупен като първия, тъй като все още наследява копие на сесията и нейната връзка, дефинирана локално в main .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да покажа текущата настройка за нулев изход в PostgreSQL (psql)

  2. Потребителски дефинирани променливи в PostgreSQL

  3. SQLAlchemy, Psycopg2 и Postgresql COPY

  4. Как да разберете дали upsert е актуализация с PostgreSQL 9.5+ UPSERT?

  5. Как да получа min, медиана и максимум от моята заявка в postgresql?