| 307 | traceback=traceback, request=request) |
| 308 | |
| 309 | def chord_error_from_stack(self, callback, exc=None): |
| 310 | app = self.app |
| 311 | |
| 312 | try: |
| 313 | backend = app._tasks[callback.task].backend |
| 314 | except KeyError: |
| 315 | backend = self |
| 316 | |
| 317 | # Handle group callbacks specially to prevent hanging body tasks |
| 318 | if isinstance(callback, group): |
| 319 | return self._handle_group_chord_error(group_callback=callback, backend=backend, exc=exc) |
| 320 | # We have to make a fake request since either the callback failed or |
| 321 | # we're pretending it did since we don't have information about the |
| 322 | # chord part(s) which failed. This request is constructed as a best |
| 323 | # effort for new style errbacks and may be slightly misleading about |
| 324 | # what really went wrong, but at least we call them! |
| 325 | fake_request = _create_fake_task_request( |
| 326 | task_id=callback.options.get("task_id"), |
| 327 | errbacks=callback.options.get("link_error", []), |
| 328 | **callback |
| 329 | ) |
| 330 | try: |
| 331 | self._call_task_errbacks(fake_request, exc, None) |
| 332 | except Exception as eb_exc: # pylint: disable=broad-except |
| 333 | return backend.fail_from_current_stack(callback.id, exc=eb_exc) |
| 334 | else: |
| 335 | return backend.fail_from_current_stack(callback.id, exc=exc) |
| 336 | |
| 337 | def _handle_group_chord_error(self, group_callback, backend, exc=None): |
| 338 | """Handle chord errors when the callback is a group. |