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

DATAUP-729 - ts/last_checked for STATUS requests/response, unify output state errors #2891

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

n1mus
Copy link
Contributor

@n1mus n1mus commented Apr 14, 2022

Description of PR purpose/changes

  • Please include a summary of the change and which issue is fixed.
  • Please also include relevant motivation and context.
  • List any dependencies that are required for this change.

Jira Ticket / Issue

Related Jira ticket: https://kbase-jira.atlassian.net/browse/DATAUP-X

  • Added the Jira Ticket to the title of the PR (e.g. DATAUP-69 Adds a PR template)

Testing Instructions

  • Details for how to test the PR:
  • Tests pass locally and in GitHub Actions
  • Changes available by spinning up a local narrative and navigating to X to see Y

Dev Checklist:

  • My code follows the guidelines at https://sites.google.com/lbl.gov/trussresources/home?authuser=0
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • (JavaScript) I have run Prettier and ESLint on changed code manually or with a git precommit hook
  • (Python) I have run Black and Flake8 on changed Python code manually or with a git precommit hook
  • Any dependent changes have been merged and published in downstream modules

Updating Version and Release Notes (if applicable)

@lgtm-com
Copy link

lgtm-com bot commented Apr 14, 2022

This pull request introduces 1 alert and fixes 1 when merging fa4ea85 into d6ff0d5 - view on LGTM.com

new alerts:

  • 1 for Unused import

fixed alerts:

  • 1 for Variable defined multiple times

@n1mus n1mus force-pushed the DATAUP-729-job-ts branch from fa4ea85 to fad63e7 Compare April 15, 2022 02:16
@lgtm-com
Copy link

lgtm-com bot commented Apr 15, 2022

This pull request fixes 1 alert when merging fad63e7 into 20428dd - view on LGTM.com

fixed alerts:

  • 1 for Variable defined multiple times

@n1mus n1mus force-pushed the DATAUP-729-job-ts branch 2 times, most recently from 55ed0fb to 2c275a1 Compare April 15, 2022 20:04
@lgtm-com
Copy link

lgtm-com bot commented Apr 15, 2022

This pull request fixes 1 alert when merging 2c275a1 into 20428dd - view on LGTM.com

fixed alerts:

  • 1 for Variable defined multiple times

@n1mus n1mus force-pushed the DATAUP-729-job-ts branch from 2c275a1 to 81dfcb2 Compare April 15, 2022 21:17
@n1mus n1mus changed the title DATAUP-729 - WIP DATAUP-729 - ts/last_checked for STATUS requests/response, unify output state errors Apr 15, 2022
@lgtm-com
Copy link

lgtm-com bot commented Apr 15, 2022

This pull request fixes 1 alert when merging 81dfcb2 into 20428dd - view on LGTM.com

fixed alerts:

  • 1 for Variable defined multiple times

add ts to STATUS requests
add last_checked to STATUS responses
unify error modes in response JSON
@n1mus n1mus force-pushed the DATAUP-729-job-ts branch from 81dfcb2 to 542e952 Compare April 16, 2022 00:24
@lgtm-com
Copy link

lgtm-com bot commented Apr 16, 2022

This pull request fixes 1 alert when merging 542e952 into 20428dd - view on LGTM.com

fixed alerts:

  • 1 for Variable defined multiple times

@sonarqubecloud
Copy link

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 1 Bug
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

No Coverage information No Coverage information
0.0% 0.0% Duplication

@n1mus
Copy link
Contributor Author

n1mus commented Apr 18, 2022

Looked through some of the issues flagged by the bots but I didn't think most of them were really critical.

@n1mus n1mus marked this pull request as ready for review April 18, 2022 17:17
@@ -100,7 +98,7 @@ def __init__(self, ee2_state, extra_data=None, children=None):
if ee2_state.get("job_id") is None:
raise ValueError("Cannot create a job without a job ID!")

self._acc_state = ee2_state
self._update_state(ee2_state)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Trying to route all Job._acc_state updates through job._update_state to get the job.last_updated updated appropriately

@@ -325,20 +323,30 @@ def _update_state(self, state: dict) -> None:
"""
given a state data structure (as emitted by ee2), update the stored state in the job object
"""
if state:
if not isinstance(state, dict):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some refactor--being more specific about what this method should accept anyway

self._acc_state = state
else:
self._acc_state.update(state)
# Check if there would be no change in updating
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check if incoming state would cause any changes

if {**self._acc_state, **state} == self._acc_state:
return

state = copy.deepcopy(state)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Update and timestamp job.last_updated


def state(self, force_refresh=False):
def state(self, force_refresh=False, exclude=JOB_INIT_EXCLUDED_JOB_STATE_FIELDS):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Move the default exclude to a more controllable position in the method header

Copy link
Collaborator

Choose a reason for hiding this comment

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

can you call this variable something more descriptive, like excluded_fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, that is more consistent


def _internal_state(self, exclude=None):
"""Wrapper for self._acc_state"""
state = copy.deepcopy(self._acc_state)
self._trim_ee2_state(state, exclude)
return state

def output_state(self, state=None) -> dict:
def output_state(self, state=None, no_refresh=False) -> dict:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add no_refresh parameter so that jm._construct_job_state_set can ask for the stagnant output state when EE2 won't cooperate

Comment on lines -378 to -385
errormsg: optional - string,
error (optional): {
code: int,
name: string,
message: string (should be for the user to read),
error: string, (likely a stacktrace)
},
error_code: optional - int
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This output state I didn't find particularly helpful. Just looking at the "optional" error stuff seemed like a violation of helpful documentation. I concluded a long time ago that the error output state would probably be never triggered, and it's kind of mutually exclusive with the regular output state

Copy link
Collaborator

Choose a reason for hiding this comment

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

The error output state is triggered by an app failing somehow, which can happen pretty easily with some apps.

Here's the job state from an App Sleep job that I configured to fail:

{
  "status": "error",
  "updated": 1650382783214,
  "queued": 1650382769657,
  "batch_job": false,
  "child_jobs": [],
  "retry_ids": [],
  "retry_count": 0,
  "job_id": "625ed7b128c29d4fd84dcf3a",
  "batch_id": null,
  "created": 1650382769000,
  "running": 1650382777753,
  "finished": 1650382783129,
  "errormsg": "Job output contains an error",
  "error": {
    "code": -32000,
    "name": "Server error",
    "message": "'App woke up from its nap very cranky!'",
    "error": "Traceback (most recent call last):\n  File \"/kb/module/bin/../lib/NarrativeTest/NarrativeTestServer.py\", line 101, in _call_method\n    result = method(ctx, *params)\n  File \"/kb/module/lib/NarrativeTest/NarrativeTestImpl.py\", line 345, in app_sleep\n    raise RuntimeError('App woke up from its nap very cranky!')\nRuntimeError: App woke up from its nap very cranky!\n"
  },
  "error_code": 1,
  "job_output": {}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh ... I guess that comes from EE2. I had given up on EE2 documentation because I wasn't sure how up-to-date the spec was, which was why I wished for documentation on that, instead of having to elicit output from the narrative in manifold imaginative ways.

Comment on lines +20 to +21
NO_INPUT_TYPE_ERR = "Please provide one of job_id, job_id_list, or batch_id"
ONE_INPUT_TYPE_ONLY_ERR = "Please provide at most one of job_id, job_id_list, or batch_id"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thought this was a real distinction but now I'm not so sure with the reconfigured request types ...

Copy link
Collaborator

Choose a reason for hiding this comment

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

The frontend can't do anything useful with this info so really all these errors could be replaced by NO_INPUT_TYPE_ERR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure

def __init__(self, rq: dict):
self.raw_request = copy.deepcopy(rq)
rq = copy.deepcopy(rq)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Extra protection since the request dict directs all subsequent execution

Comment on lines +73 to +76
if not self.rq_data:
raise JobRequestException(INVALID_REQUEST_ERR)
self.request_type = self.rq_data.get("request_type")
if self.request_type is None:
if not self.request_type:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the falsy values, {} or "", should be just as invalid and should be handled instead of just let through

Comment on lines -190 to -191
except Exception as ex:
raise JobRequestException(ONE_INPUT_TYPE_ONLY_ERR) from ex
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what this was for? removed it

Copy link
Collaborator

Choose a reason for hiding this comment

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

If you look at the implementation of req.job_id_list, it returns req.job_id as a list if there was no job_id_list parameter.

Copy link
Contributor Author

@n1mus n1mus Apr 29, 2022

Choose a reason for hiding this comment

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

req.job_id_list doesn't raise any exceptions except for its own JobRequestException?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Then JOBS_NOT_PROVIDED_ERR should be "job_id or job_id_list not provided"?

Comment on lines +224 to 229
"source": getattr(e, "source", "jc.start_job_status_loop"),
"request": getattr(e, "request", "jc.start_job_status_loop"),
"name": getattr(e, "name", type(e).__name__),
"message": getattr(e, "message", UNKNOWN_REASON),
"error": "Unable to get initial jobs list",
"code": getattr(e, "code", -1),
Copy link
Contributor Author

@n1mus n1mus Apr 18, 2022

Choose a reason for hiding this comment

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

Trying to order these job comm error fields consistently and meaningfully

"""
job_id_list = self._get_job_ids(req)
job_info = self._jm.get_job_info(job_id_list)
self.send_comm_message(MESSAGE_TYPE["INFO"], job_info)
return job_info

def __get_job_states(self, job_id_list) -> dict:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If being totally pedantic the leading dunderscore is for name mangling in times of subclassing

Copy link
Collaborator

Choose a reason for hiding this comment

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

can you give this method a better name than _get_send_job_states, in that case? e.g. _get_job_states_from_job_id_list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You would invoke it as _get_send_job_states(job_ids) anyway? And the send part is also important to the story

"""
output_states = self._jm.get_job_states(job_id_list)
output_states = self._jm.get_job_states(job_id_list, ts)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add ts in this downstream STATUS-esque method

job_id_list = self._get_job_ids(req)
return self.__get_job_states(job_id_list)
return self._get_send_job_states(job_id_list, req.ts)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add ts for STATUS requests

"""
error_content = {}
if isinstance(req, JobRequest):
error_content["request"] = req.rq_data
error_content["source"] = req.request_type
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maintain the order of the error fields consistently throughout code

Copy link
Collaborator

Choose a reason for hiding this comment

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

reverse alphabetical?

DOES_NOT_EXIST = "does_not_exist"


class OutputStateErrMsg(Enum):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Decided to turn output state errors into an Enum and not sure if I got carried away adding instance methods and coupling that to jm.add_errors_to_results

Copy link
Collaborator

Choose a reason for hiding this comment

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

This does seem a little like an excuse to use Enums... 😁

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I think Enum is fine but I may have gone overboard when I found out each enum could act as an instance ...

QUERY_EE2_STATES = "A Job.query_ee2_states error occurred for job with ID %s: %s"
CANCEL = "An EE2.cancel_job error occurred for job with ID %s: %s"

def gen_err_msg(self, its: List[Union[str, int, Iterable]]):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be used with jm.add_errors_to_results. Returns iterable that will return errors formatted with appropriate args (i.e., error_ids, other error msg information)

Copy link
Collaborator

Choose a reason for hiding this comment

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

How are you handling error messages that come back from ee2? Just passing them through as-is?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe that was the original behavior which I preserved.


return gen()

def replace_result(self) -> bool:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tells whether the particular enum error is meant to replace the dict in the results dict, or if if is meant to be added onto the existing dict

"return_list": 0,
}
)
job_states = Job.query_ee2_states(job_ids, init=True)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactoring the ee2.check_jobs mainly because that's another way to increase the psychological chokepoint-ness of updated job._acc_state ... at least in the sense that it DRYs things up and reduces cognitive load

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sensible. Ideally all of the ee2 methods would be in one place, but that's probably a refactor too far...

"""
job_ids, error_ids = self._check_job_list(job_id_list)
error_states = dict()
error_states = {}
for job_id in job_ids:
if not self.get_job(job_id).was_terminal():
error = self._cancel_job(job_id)
if error:
error_states[job_id] = error.message

job_states = self._construct_job_output_state_set(job_ids)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So I realized here you can theoretically can an EE2 error AND a cancel job error for the same job ID. So I made sure that errors were recursively concatenateable

Comment on lines +799 to +801
def add_errors_to_results(
results: dict, error_ids: List[str], error_enum: OutputStateErrMsg, *extra_its: Tuple
) -> dict:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Takes the results dict, error_ids, the error enum, and any extra err msg formatting args

Comment on lines +18 to +19
with open(os.path.join(*full_path)) as fh:
config = json.load(fh)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this is the pythonic way to make sure the resource is closed

Comment on lines 18 to +19
"""
generate_test_results.py is used to generate the job message data that the narrative backend produces and that the frontend consumes. It uses data from `ee2_job_test_data_file` and `app_specs_file` and provides expected narrative backend message data, as well as a number of mappings that are used in python tests.
generate_test_results.py is used to generate the job message data that the narrative backend produces and that the frontend consumes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Introduced line breaks since my IDE is not set to line wrap

Copy link
Collaborator

Choose a reason for hiding this comment

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

What?! Which IDE are you using? Do you just not have line wrapping turned on?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

VSCode. So I can see when I'm being naughty and going too long?

@@ -108,7 +115,7 @@


def make_comm_msg(
msg_type: str, job_id_like, as_job_request: bool, content: dict = None
msg_type: str, job_id_like, as_job_request: bool, content: dict = {}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactor

@@ -134,6 +140,20 @@ def get_app_data(*args):
return {"info": {"name": APP_NAME}}


def ts_are_close(t0: int, t1: int, tol: float = 1) -> bool:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For when not mocking out biokbase.narrative.jobs.jobcomm.time.time_ns with 42, check that last_checked ts is approximately right

@@ -366,6 +386,22 @@ def test_req_no_inputs__fail(self):

for msg_type in functions:
req_dict = make_comm_msg(msg_type, None, False)
err = JobRequestException(NO_INPUT_TYPE_ERR)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tease out cases for NO_INPUT_TYPE_ERR and ONE_INPUT_TYPE_ONLY_ERR

"source": "ee2",
"request": "jc.start_job_status_loop",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Re-order job comm error fields order

Comment on lines +555 to +558
if response_type == STATUS:
self._check_pop_last_checked(output_states, last_checked)
else:
self.assertNotIn("last_checked", output_states)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Easiest way to test the last_checked field compatibly with existing test harnessing is to check it then delete it

Comment on lines +708 to +712
# output_states will be partitioned as
not_found_ids
terminal_ids = list(set(job_ids) - set(ACTIVE_JOBS))
not_updated_active_ids = list(set(not_updated_ids) & set(active_ids))
updated_active_ids = list(set(updated_ids) & set(active_ids)) # (yes, redundant)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the whole point of this test is to check that the mechanism for replacing not updated jobs with error stubs works. The most important part is to distinguish between terminal_ids and not_updated_active_ids, which should be given error stubs, from updated_active_ids which should send back actual output states

Comment on lines +1430 to +1442
rq_msg1 = {"msg_id": "some_id", "content": {}}
rq_msg2 = {"msg_id": "some_id", "content": {"data": {}}}
rq_msg3 = {"msg_id": "some_id", "content": {"data": None}}
rq_msg4 = {"msg_id": "some_id", "content": {"what": "?"}}
for msg in [rq_msg1, rq_msg2, rq_msg3, rq_msg4]:
with self.assertRaisesRegex(JobRequestException, INVALID_REQUEST_ERR):
JobRequest(msg)

def test_request_no_req(self):
rq_msg = {"msg_id": "some_id", "content": {"data": {"request_type": None}}}
rq_msg2 = {"msg_id": "some_other_id", "content": {"data": {}}}
for msg in [rq_msg, rq_msg2]:
rq_msg1 = {"msg_id": "some_id", "content": {"data": {"request_type": None}}}
rq_msg2 = {"msg_id": "some_id", "content": {"data": {"request_type": ""}}}
rq_msg3 = {"msg_id": "some_id", "content": {"data": {"what": {}}}}
for msg in [rq_msg1, rq_msg2, rq_msg3]:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Testing for other falsy things. Before, only None was considered invalid

@@ -640,6 +645,67 @@ def test_get_job_states__empty(self):
):
self.jm.get_job_states([])

@mock.patch(CLIENTS, get_mock_client)

This comment was marked as outdated.

@@ -740,6 +806,219 @@ def test_get_job_info(self):
infos, {id: ALL_RESPONSE_DATA[MESSAGE_TYPE["INFO"]][id] for id in ALL_JOBS}
)

@mock.patch(CLIENTS, get_mock_client)
def test_add_errors_to_results__concat_errs__integrated(self):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test concat errors (i.e., in the case that jm.cancel_jobs needs to concat an error from an output state from jm._construct_output_state_set

output_state["error"]
)

def test_add_errors_to_results__cannot_add_err(self):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test when trying to add error to existing dict in the results dict in jm.add_errors_to_results but there's no corresponding dict there

)


class OutputStateErrMsgTest(unittest.TestCase):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unit tests for the enum class OutputStateErrMsg

@n1mus n1mus requested review from ialarmedalien and briehl April 18, 2022 20:04
or when it is retrieved from a cache. If not supplied, must be
queried with self.state() or self._internal_state()
:return: dict - with structure generally like (not accounting for error modes):
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

The extra padding here is a waste of space and it forces some of the longer lines to wrap, decreasing legibility.

}
}
}

This little wrapper fills 2 roles:
This little wrapper fills some roles:
Copy link
Collaborator

Choose a reason for hiding this comment

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

"some" sounds strange -- can you change it to "two"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought "some" was more a scaffold type documentation, since I was just deleting obsolete documentation and smoothing over the difference

into multiple JobRequests. Likewise, if the job comm channel request data
is received with a job_id, a JobRequest may be created with a job_id_list
containing that job_id
2. It provides any job ID information with guardrails
Copy link
Collaborator

Choose a reason for hiding this comment

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

?? guardrails?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just trying to delete obsolete documentation and smooth it over. The guardrails are in the code

Comment on lines +200 to +201
if not req.has_job_ids():
raise JobRequestException(NO_INPUT_TYPE_ERR)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unneeded -- this was already handled by the code you deleted.

There isn't any need for distinction between NO_INPUT_TYPE_ERR and ONE_INPUT_TYPE_ONLY_ERR because the job request is sent back with the error and the frontend can't do anything helpful with the error message other than output it to the console.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, ONE_INPUT_TYPE_ONLY_ERR sounded to me like there were too many input types

@@ -114,6 +115,11 @@ def cell_id_list(self):
return self.rq_data[PARAM["CELL_ID_LIST"]]
raise JobRequestException(CELLS_NOT_PROVIDED_ERR)

@property
def ts(self):
"""This param is completely optional"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we have a better description than this?

Comment on lines +368 to +372
failed_ids = [job_id for job_id in jobs_to_lookup if job_id not in fetched_states]
if failed_ids:
self.add_errors_to_results(
output_states, failed_ids, OutputStateErrMsg.QUERY_EE2_STATES, error_message
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is now more complex than it was, so I'm not sure it is an improvement...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the Enum with all its glory may not have been great as it did add complexity. But I think here it's streamlined because you have a method that takes the output data structure, the id keys, the error message, and also concatenates errors instead of overwriting them. So, cancel_jobs calls this method, so the output data structure can accrue both a ee2.check_jobs error and a ee2.cancel_jobs error.

Also, if you look at python library packages, the code can be really stupid complex. So I may be erring on the side of complexity.

Comment on lines +435 to +436
self.add_errors_to_results(output_states, not_found_ids, OutputStateErrMsg.NOT_FOUND)
self.add_errors_to_results(output_states, not_updated_ids, OutputStateErrMsg.NOT_UPDATED, ts)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unfortunately this is not what I asked for in the Jira ticket -- if a job hasn't been updated, the BE is supposed just to omit it from the results it returns.

Once the docs PR is merged and this PR is rebased on develop, I'll set this up locally and do some experimenting.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the description was a little more open-ended and inconsistent with the acceptance critera. So I interpreted the entire JIRA ticket as being open-ended.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, I think I got completely tripped up by this part of the ticket

don’t include the jobState dict in the job output, just return job_id and last_checked for each job in the request?

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.

2 participants