3

My question is about more philosophical than technical issues.

A few words about Doctrine`s EM. It closes connection and clear itself if any exception occurred during it work: connection to database failed (common case in long-running consumers with low number of incoming tasks), error in SQL statement, or something else, related to DB-server, or EM itself. After this EM instance is completely unusable.

So, real-world example: i have a queue and consumer, that`s running as console worker and wait for tasks. Consumer has next dependencies:

  • EntityManager (EM)
  • Service1 -> has dependency from EM and Doctrine Repository1
  • Service2 -> has dependency from EM and Doctrine Repository2
  • ServiceN -> has dependency from EM and Doctrine RepositoryN

If EM service is failed - Service(1-N) and Repository(1-N), that depends on this EM, will be also throw errors when called, because EM is no longer works correctly. What I should do in this case?

  1. "let-it-crash": worker stoppped with error and later reloaded by supervisord. Leads to increase number of useless errors in logs\stderr.
  2. do some magic with $connection->ping() in each iteration: actually, ping() just execute SELECT 1;, so, this leads to increase number of useless queries to DB server.
  3. same as before, but in case of EM fail create new one on consumer: execute ping() on each iteration, if it failed - create new EM. But, all services used in consumer should be also re-created, so I need a Factory for each of them. This way leads to increase number of classes and more complicated logic in consumer: re-create all services (and it dependencies) on each iteration with new, or old EM, or detect EM re-creation and re-create all dependent services only in case of new EM. But this leads to abstaction leak: consumer should not know what EM instance it uses - old or new, and should not do this crappy things.

What is the best way to deal with this things?

Vladislav Rastrusny
  • 29,378
  • 23
  • 95
  • 156
Alex
  • 571
  • 1
  • 8
  • 26

1 Answers1

1

I would share some thoughts here.

  1. "Leads to increase number of useless errors in logs\stderr" - I do not think these are useless errors. If your software throws an exception, you should know about that. A log file of the software is best when it doesn't have any exceptions, but that's rarely the case. Anyway, any database exception and a rate at which it occurs, should be investigated.

  2. I would not rely on reestablishing connection, but instead rely on Doctrine API to initialize itself. This answer has some details on how to do that for several Doctrine2 versions.

  3. I think this is too much of the logic to implement and will only complicate matters.

If I were to choose, I would go with option #1 (let-it-crash) because it is the simpliest of all and it does not hide anything from us.

Community
  • 1
  • 1
Vladislav Rastrusny
  • 29,378
  • 23
  • 95
  • 156
  • 1
    Under "useless error" I mean exceptions like "mysql connection has gone away", that raised in case, when worker do not receive any tasks from queue and DB server close idle connection by timeout. For example, if connection timeout is one minute and tasks generated each 1.5-2 minute (real-world example), for 24 hours I will receive ~720 errors\exceptions. And this is only for one worker. Also, supervisord log will be filled with "noise", that generated this "crash-restart" cycles, and find real errors can be more hard to detect. – Alex Mar 06 '17 at 09:54
  • 1
    As for ``resetManager()``, I already use this approach, but this works only for EM and repositories, obtained by ``$em->getRepository()``. All other services stay unusable, until re-created with factory. – Alex Mar 06 '17 at 10:05