Page MenuHomePhabricator

Creating a cyclic task dependency in Maniphest no longer produces a nice error dialog
Closed, ResolvedPublic

Description

I noticed this while testing the patch for T6757, but when you create a cyclic dependency, I no longer get a nice error dialog. Specifically, to reproduce, for any pair of tasks:

  • Add T2 as a blocker of T1.
  • Now, add T1 as a blocker of T2.

Expected behavior:

  • Nice error dialog saying "you can't do that, you'd create a dependency cycle".

Actual behavior:

  • Server-side unhandled exception.

Some notes:

  • Relevant code is in PhabricatorSearchAttachController.
  • We seem to throw PhabricatorEdgeCycleException correctly. This raises out of an EdgeEditor inside the TransactionEditor which does most of the work.
  • The controller has code to convert this into a human-readable message, in raiseGraphCycleException(), but it is never called.

Some approaches might be:

  • Use blame to track down what removed raiseGraphCycleException() and see what it used to do, then do that if it's easy.
  • Use return $this->newDialog(...) to just return a dialog explicitly.
  • (Probably overreaching) Improve top-level exception handling? I think we used to get some kind of dialog back on unhandled exceptions. This might be configuration-dependent. Sending anything back would be significantly better than the current behavior. Providing a PhabricatorUsageException($message) or similar -- which serves as a hint that the message is user-friendly and we can always shows the message details, regardless of configuration settings -- might be a step up from that. This might get resolved by, e.g., T6692 before this gets tackled, and provide a more straightforward approach.

Event Timeline

epriestley renamed this task from Creating a cyclic dependency no longer produces a nice error dialog to Creating a cyclic task dependency in Maniphest no longer produces a nice error dialog.
epriestley raised the priority of this task from to Low.
epriestley updated the task description. (Show Details)
epriestley added a subscriber: epriestley.

Ah, thanks! Looks like I just overlooked it when merging the edge / transaction blocks, so nothing nefarious.

Seems like I fixed the top-level handling issue at some point (?) -- maybe during T6692 -- since I get this, although @mpalmer reports only getting a log in T7433 (maybe you're a little out of date?):

Screen_Shot_2015-03-02_at_2.57.31_PM.png (170×1 px, 32 KB)

Running on 18340d9 here; I'll be upgrading in the next couple of hours to master to fix T7421 if you'd like a retest. Looking at T6692, though, it looks like that was fixed back in Jan.

Yeah, I'm pretty sure there aren't any relevant changes between rP18340d9 and HEAD. If it isn't resolved the next time you upgrade, let me know and I'll dig a bit deeper.

Just upgraded to e5e3eb3 and the problem still persists. Same UI, and the log message looks much the same to me:

PHP message: [2015-03-03 11:35:03] EXCEPTION: (PhabricatorEdgeCycleException) Graph cycle detected (type=3, cycle=PHID-TASK-i64i4tkbh6ug5uclenqv, PHID-TASK-6tgvodi4uo5klx3mz4hx, PHID-TASK-i64i4tkbh6ug5uclenqv). at [<phabricator>/src/infrastructure/edges/editor/PhabricatorEdgeEditor.php:401]
PHP message: arcanist(head=master, ref.master=4e9845484049), phabricator(head=master, ref.master=e5e3eb357fa0), phutil(head=master, ref.master=b6200342f224)
PHP message:   #0 PhabricatorEdgeEditor::detectCycles(array, integer) called at [<phabricator>/src/infrastructure/edges/editor/PhabricatorEdgeEditor.php:129]
PHP message:   #1 PhabricatorEdgeEditor::save() called at [<phabricator>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:481]
PHP message:   #2 PhabricatorApplicationTransactionEditor::applyExternalEffects(ManiphestTask, ManiphestTransaction) called at [<phabricator>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:717]
PHP message:   #3 PhabricatorApplicationTransactionEditor::applyTransactions(ManiphestTask, array) called at [<phabricator>/src/applications/search/controller/PhabricatorSearchAttachController.php:89]
PHP message:   #4 PhabricatorSearchAttachController::processRequest() called at [<phabricator>/src/aphront/AphrontController.php:33]
PHP message:   #5 AphrontController::handleRequest(AphrontRequest) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:196]
PHP message:   #6 AphrontApplicationConfiguration::processRequest(AphrontRequest, PhutilDeferredLog, AphrontPHPHTTPSink) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:121]
PHP message:   #7 AphrontApplicationConfiguration::runHTTPRequest(AphrontPHPHTTPSink) called at [<phabricator>/webroot/index.php:19]

Haha, sorry, I hadn't actually committed the fix yet.

I'm still getting the blank, greyed-over screen, running on d866af3. The exception message is improved, but it's still only showing up in the logs:

PHP message: [2015-03-03 14:16:33] EXCEPTION: (Exception) You can not create that dependency, because it would create a circular dependency: T498: [1] Add giddyup to digifind. → T106: [1] Setup a Staging site for Digifind → T498: [1] Add giddyup to digifind.. at [<phabricator>/src/applications/search/controller/PhabricatorSearchAttachController.php:330]
PHP message: arcanist(head=master, ref.master=4e9845484049), phabricator(head=master, ref.master=d866af32e0af), phutil(head=master, ref.master=b6200342f224)
PHP message:   #0 PhabricatorSearchAttachController::raiseGraphCycleException(PhabricatorEdgeCycleException) called at [<phabricator>/src/applications/search/controller/PhabricatorSearchAttachController.php:93]
PHP message:   #1 PhabricatorSearchAttachController::processRequest() called at [<phabricator>/src/aphront/AphrontController.php:33]
PHP message:   #2 AphrontController::handleRequest(AphrontRequest) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:196]
PHP message:   #3 AphrontApplicationConfiguration::processRequest(AphrontRequest, PhutilDeferredLog, AphrontPHPHTTPSink) called at [<phabricator>/src/aphront/configuration/AphrontApplicationConfiguration.php:121]
PHP message:   #4 AphrontApplicationConfiguration::runHTTPRequest(AphrontPHPHTTPSink) called at [<phabricator>/webroot/index.php:19]
PHP message: PHP Fatal error:  Uncaught exception 'Exception' with message 'Process exited with an open transaction! The transaction will be implicitly rolled back. Calls to openTransaction() must always be paired with a call to saveTransaction() or killTransaction().' in /home/phabricator/production/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php:69
Stack trace:
#0 [internal function]: AphrontDatabaseTransactionState->__destruct()
#1 {main}
  thrown in /home/phabricator/production/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php on line 69

Hrrm, I'm having a hard time reproducing this and don't immediately see anything in the code which could cause us to drop the dialog.

Does it reproduce for you on this install? You can try adding this as a blocker for T7437. I get the dialog:

Screen_Shot_2015-03-03_at_4.02.55_AM.png (1×1 px, 146 KB)

I get the dialog on this installation. However, try as I might, I can't get it to pop up on ours. Same browser, settings, etc. Would a capture of the HTTP traffic on my install help to narrow down whether the problem is in the PHP code not reporting the error correctly, or the client-side JS not handling it correctly?

If it's not too hard, it would likely be helpful.

I can just replace this with a dialog, too, which should fix the problem, but I'd like to understand the root issue behind the exception thing.

If it's not too hard, it would likely be helpful.

Coming up shortly...

I can just replace this with a dialog, too, which should fix the problem, but I'd like to understand the root issue behind the exception thing.

That's entirely reasonable.

The caffeine's finally kicked in, and I realised I could just ask Chrome to show me what both sites were doing differently...

Turns out, my installation's returning a 500 error on the exception, whereas this one is sending back the error under a 200 OK. The rest of the response (headers, body) is practically identical. In both cases it's a chunk of JSON (although with a text/plain Content-Type, *cough*) that contains the exception message and a whole bunch of extra Javelin gubbins.

To make sure it wasn't my frontend webserver doing some sort of response code transmutation, I captured the FCGI traffic between the webserver and PHP-FPM, and sure enough, it's definitely PHP giving back the 500.

Since the last time I used PHP in anger is nothing but a hazy memory, I'm not sure where to go next. Are there any PHP settings you're aware of that might cause your exception reporting code to return a 500 response instead of a 200? Possibly a PHP version issue (I'm running a Debian-patched 5.4.36)? If you have no ideas, I'll poke and prod, but it'd save me a lot of swearing if you happened to know what I've configured wrong, off the top of your head. <grin>

Ah, that's helpful. I think we explicitly set the response code to 500, so the 200 is the surprising/unexpected behavior. That should be enough for me to figure out what's going on here, thanks!

I believe D16166 resolves this. See T11179 and T4788 for followups.