Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ContainerFuture propagates error from logs #416

Merged
merged 8 commits into from
May 17, 2021

Conversation

elsander
Copy link
Contributor

The Civis API currently returns 'error': None when a Python/R/container script fails, so API client users don't get any information about what caused the failure. CivisML works around this by returning error logs to the user in these cases. This PR moves this behavior from ModelPipeline to ContainerFuture so that users can get more informative errors when running jobs outside of CivisML as well.

This is something of a workaround, especially since R client users won't get the benefits. Longer-term, we'd like to get more informative errors directly from the API.

@@ -376,8 +376,9 @@ def test_result_success(mock_civis):
# Test that we can get a result back from a succeeded job.
callback = mock.MagicMock()
mock_civis.io.civis_to_file.side_effect = make_to_file_mock('spam')
fut = ContainerFuture(1, 2, client=mock.MagicMock())
fut.set_result(Response({'state': 'success'}))
mock_client = create_client_container_mock(1, 2, state='success',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ContainerFuture now has a callback during init, so we can't get away with initializing and setting a result directly during testing. I got around this by moving the container-focused client mock from CivisML to the general tests and using it when initializing the future.

res = civis.parallel._CivisBackendResult(fut, callback)
fut._set_api_exception(CivisJobFailure(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

h/t @stephen-hoover for noticing that the arguments to _set_api_exception were not actually the expected order/type here (although the test happened to pass anyway).

CHANGELOG.md Outdated Show resolved Hide resolved
civis/tests/test_futures.py Outdated Show resolved Hide resolved
civis/tests/mocks.py Outdated Show resolved Hide resolved
civis/futures.py Show resolved Hide resolved
Copy link

@stephen-hoover stephen-hoover left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of my comments about this change are about the ModelFuture. Let me know if it's not clear where in the code some of my comments are pointing.

civis/futures.py Show resolved Hide resolved
@@ -527,7 +502,7 @@ def _set_model_exception(fut):
# If there's no metadata file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub won't let me comment too far away from this PR's changes; so this is the closest I can get. This comment is for the new L474, def _set_model_exception(fut). I suggest that you rename ModelFuture._set_model_exception to ModelFuture._set_job_exception. That way the call to the superclass's __init__ will set the subclass's version of the callback. With the current code, it looks like we'll never reach the _set_model_exception callback, since we'll first call ContainerFuture._set_job_exception, and that will set _exception_handled to True.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Stephen, I updated the name and took out the repeated callback attributes in the init. It seems to be working properly, but I had to move some of the other attributes being set in the init to above the super().__init__() since the _set_job_exception method relies on some of those properties being set.

civis/futures.py Show resolved Hide resolved
Comment on lines 63 to 64
c = mock.Mock()
c.__class__ = APIClient

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about starting with the auto-specced client mock? The autospecs can be very helpful with testing. There's also a couple of places where the return of this function is now replacing create_client_mock(), so those tests would lose their autospecs.

Suggested change
c = mock.Mock()
c.__class__ = APIClient
c = create_client_mock()

civis/tests/mocks.py Outdated Show resolved Hide resolved
@ggarcia-civis
Copy link
Contributor

@stephen-hoover @mheilman Sorry about the long wait period. I tried to address all of the remaining feedback.

@stephen-hoover
Copy link

@ggarcia-civis , I'm unlikely to be able to re-review in a timely fashion, so I will leave this review to @mheilman .

@stephen-hoover stephen-hoover removed their request for review May 13, 2021 23:15
@stephen-hoover stephen-hoover dismissed their stale review May 13, 2021 23:16

Unable to re-review to validate changes.

Copy link
Contributor

@mheilman mheilman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there are some leftover print statements from debugging, but this seems good otherwise.

@@ -379,13 +379,16 @@ def test_set_model_exception_unknown_error():
fut = _model.ModelFuture(1, 2, client=mock_client)
with pytest.raises(CivisJobFailure) as err:
fut.result()
print(str(err))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this left over from debugging?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup 😅 thanks

@ggarcia-civis
Copy link
Contributor

Hi @elliothevel, Mike is on PTO this week. Can you pick up on this PR review?

Copy link
Contributor

@elliothevel elliothevel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

jacksonlee-civis added a commit that referenced this pull request Nov 9, 2021
…re (#426)

* ENH add job and run IDs to CivisJobFailure

* MAINT update changelog

* ENH move #416 changes from ContainerFuture to CivisFuture

* FIX adjust ContainerFuture and tests

* ENH log retrieval works for CivisFuture more generally

* RM _poll_and_set_api_result (should've been rm-ed at #425)

* MAINT update changelog

* TST make ModelFuture tests work with client.jobs.list_runs_logs

* TST update mock client for ModelFuture tests

* TST more clean-up for ModelFuture tests

* FIX comment

* ENH rewrite logic to add job/run ID in CivisJobFailure

* TST refactor _create_poller_mock

* TST poller call count for poll_on_creation True/False

* ENH more natural log message order

* ENH wait for delayed traceback in log

* ENH clearer error message

* ENH simplify error message a bit

* TST revert unnecessary tweak
@jacksonlee-civis jacksonlee-civis added this to the v1.16.0 milestone Nov 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants