The MigrateExecutable::import() loop over rows to import calls processRow() to run the process plugins, and only catches MigrateSkipRowException. This means that process plugins have no means to signal errors. We should catch MigrateException, saving the provided status in the map table and logging the provided message to the front end.
The fact that MigrateSkipRowException is caught here and marks the row IGNORED in the map table seems a bit of a WTF to me, given the processing pipeline seems a little late to be deciding a row isn't "officially" part of the source (it's meant for use in prepareRow()). I want to review any existing uses of SkipRow from process plugins and see how they're using this.
Comment | File | Size | Author |
---|---|---|---|
#19 | interdiff.txt | 1.16 KB | mikeryan |
#19 | handle_migrateexception-2559571-19.patch | 4.13 KB | mikeryan |
Comments
Comment #2
mikeryanQuick first pass - obviously needs tests, and as I said I want to look at the SkipRow handling here as well, but the weekend beckons...
Comment #4
mikeryanI'll need to update the existing tests to reflect the removal of the redundant display() call. Broadening the scope to reflect that change.
Comment #5
mikeryanFixing the tests for the display() removal requires #2560435: Need an API for retrieving migration messages.
Comment #6
mikeryanUnblocked.
Comment #7
mikeryanHere it is, with tests.
A word on removing the
$this->message->display()
(and not adding it to the new catch())... display() is meant for messages that go directly to the front-end (drush terminal or web UI page), and my feeling is that the detailed per-row messages should not be sent through display(). My experience is that in many cases, the volume there can be overwhelming and hide more immediately useful messages (like a migration being skipped if dependencies aren't met) - these detailed messages are best reviewed at leisure (yes, I need to implement message viewing in migrate_tools). If there's a strong feeling otherwise, then we should not be expected to always pair calls to saveMessage() and display(), but rather have saveMessage() itself call display().Better yet, it would be best if the id map plugin had a boolean option whether to display logged messages... Hmmm...
Comment #8
phenaproximaLooks good overall.
What is this doing?
Not crucial, but I think that for readability we can use willReturn() and willThrow() everywhere in this test.
Comment #9
mikeryanThe idea was that we shouldn't abort the row on mere informational/notice messages. However, since we're in an exception handler, if the exception was thrown some of the processing was skipped, so we don't know the integrity of the row, so I've taken that out. Process plugins should not throw informational/notice-level exceptions, they should call saveIdMapping themselves.
Done!
Comment #10
mikeryanOops.
Comment #12
phenaproximaSo one thing that I realize -- because of this patch, it looks like we may no longer be saving rows that throw MigrateExceptions. Is this consistent with what we're already doing? If not, I can see that causing all sorts of pain...
Then again, it does pass all the tests, so maybe my fear is misplaced.
Comment #13
mikeryanWe weren't previously catching MigrateException here, so it would get caught somewhere farther up the chain and not only would the current row not be saved, the whole thing would be aborted. No one's throwing MigrateException at this time from a process plugin anyway (although I believe @neclimdul is planning on doing it, the initial inspiration for this whole look at messages and exceptions).
Comment #14
benjy CreditAttribution: benjy at PreviousNext commentedI think this was so that if a process plugin came across something bad, it could skip the row rather than letting the destination try to import it and cause a fatal error. The source doesn't do any validation of it's data and unfortunately neither do our destinations so process can be dealt a bad hand. This issue helps log the exception but wouldn't prevent fatals if we removed MSRE from process plugins?
why do we save $level to a variable but right below just do $e->getMessage() ?
Comment #15
benjy CreditAttribution: benjy at PreviousNext commentedAlso, I think it was mainly the migrate process plugin that needed it and we solved that here #2560671: The Migration process plugin should not skip rows
Comment #16
quietone CreditAttribution: quietone commentedApplying this patch fixes a problem with Leading slashes not added to visibility paths. In that case we don't want to migrate a block when the block visibility contains php code and the php module is not installed. That case is determined in the BlockVisibility process plugin and throwing a MigrateException with this patch works.
SkipRow didn't work because an empty visibility array is valid, and thus some blocks weren't migrated. And SkipProcess gave an error of Plugin ID '0' was not found, which I didn't investigate because mikeryan1 pointed me to this issue. Thx!
Comment #17
mikeryanThe $save = FALSE prevents the destination import from being called.
See @phenaproxima's comment a few back - I had been using $level to decide how to set $save, but then decided to just set $save FALSE. I can inline $e->getLevel() if you'd like.
Tagging "blocker", we're now blocking quietone's patch at #2532550: Leading slashes not added to visibility paths.
Comment #18
benjy CreditAttribution: benjy at PreviousNext commentedInline would be nicer but it isn't a blocker. Rest looks good to me, one question.
How can a method throw an exception and have a return value? Is the exception meant to bubble up? If so, we usually put the @expectsException on the test method doc.
Comment #19
mikeryanThe willReturn() was leftover copypasta, I think - removed. The exception is not meant to bubble up, it's meant to be caught in import() (the point of this patch, actually).
Inlined the $e->getLevel() while I was at it.
Thanks!
Comment #20
benjy CreditAttribution: benjy at PreviousNext commentedYeah I didn't think it was, but the return implied otherwise :)
Looks good.
Comment #22
webchickNothing to complain about here. :)
Committed and pushed to 8.0.x. Thanks!
Comment #23
mikeryan