-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
Optionally run Codejail in a external service using REST API. #27795
Optionally run Codejail in a external service using REST API. #27795
Conversation
Thanks for the pull request, @ericfab179! I've created OSPR-5820 to keep track of it in JIRA, where we prioritize reviews. Please note that it may take us up to several weeks or months to complete a review and merge your PR. Feel free to add as much of the following information to the ticket as you can:
All technical communication about the code itself will be done via the GitHub pull request interface. As a reminder, our process documentation is here. Please let us know once your PR is ready for our review and all tests are green. |
@ericfab179 Thank you for your contribution. Please let me know once it is ready for our review. |
c415246
to
ea761b6
Compare
@@ -6,10 +6,12 @@ | |||
from codejail.safe_exec import SafeExecException, json_safe | |||
from codejail.safe_exec import not_safe_exec as codejail_not_safe_exec | |||
from codejail.safe_exec import safe_exec as codejail_safe_exec | |||
from django.conf import settings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This import is not used in the file
} | ||
response_globals_dict, emsg = send_safe_exec_request(data, extra_files) | ||
|
||
if emsg: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this logic of creating the exception and updating the globals should be performed by send_safe_exec_request
method
def send_safe_exec_request(data, extra_files): | ||
codejail_service_endpoint = get_codejail_rest_service_endpoint() | ||
payload = json.dumps(data) | ||
response = requests.post( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about wrapping the requests call with a try-catch, similar to https://github.com/edx/edx-platform/blob/master/lms/djangoapps/edxnotes/helpers.py#L105. Notice that in the notes example, a custom exception is raised, a custom one could be used here as well since this is a critical component that impacts the user experience.
payload = json.dumps(data) | ||
response = requests.post( | ||
codejail_service_endpoint, | ||
files=extra_files, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just to have a discussion: in case of Codejail service API failure, should the platform fall back to the local execution (at least during the adoption of the remote service)?
def send_safe_exec_request(data, extra_files): | ||
codejail_service_endpoint = get_codejail_rest_service_endpoint() | ||
payload = json.dumps(data) | ||
response = requests.post( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I consider we should set a timeout for these requests, which could be configurable
609ab16
to
0773b83
Compare
""" | ||
An exception that is raised whenever Codejail service is unavailable. | ||
""" | ||
pass # lint-amnesty, pylint: disable=unnecessary-pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mariajgrimaldi We are basically copying the edxnotes structure https://github.com/edx/edx-platform/blob/master/lms/djangoapps/edxnotes/exceptions.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lint-amnesty
comments were added by a tool that allowed us to ignore existing lint failures and prevent new ones from coming in -- if you're copying code from somewhere, you'll want to resolve the lint failure instead.
In this case, you can actually get rid of the entire line, both pass
and linter comment. The pass
is apparently unneeded because the comment serves as the body of the class (this surprised me, but OK!) and that's what the linter was complaining about. I suspect that when the original code was written in notes, the comments weren't there at first, so the author added pass
to wrap up the class and then forgot to remove it later. :-)
Hi @ericfab179, we're really curious about this PR and the possibility of a codejail as a service. What are your plans for this? |
|
||
response_json = response.json() | ||
|
||
emsg = response_json["emsg"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Safer way to get the error message.
emsg = response_json["emsg"] | |
emsg = response_json.get("emsg") |
|
||
exception = SafeExecException(emsg) | ||
|
||
globals_dict.update(response_json["globals_dict"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
globals_dict.update(response_json["globals_dict"]) | |
globals_dict.update(response_json.get("globals_dict")) |
Indeed, what happens if the response does not contain a "globals_dict" key? Maybe validation is required to make sure "globals_dict" is returned and it contains proper data
|
||
globals_dict.update(response_json["globals_dict"]) | ||
|
||
except RequestException: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this exception imported? Does it throw an exception when the codejail service sends backs a HTTP status different to 2xx?
Hi @pdpinch we are in the process of internal reviews with the edunext team and as soon as we are done with that we are going to let you know for the edx review. This PR is related to this other two repositories:
|
@ericfab179 why is this pull request against Koa? Typically we make changes on master, and then backport them as needed. |
1440b01
to
21a8712
Compare
0adec99
to
f458150
Compare
Just noticed this in my notifications. @timmc-edx and some others at edX were doing some investigation around this as well during a hackathon a while back. Have you connected with him or seen the notes from that hackathon's investigation by any chance? |
One of the things I'm personally curious about from the design point of view is how much the startup costs are, and how that might be mitigated. We sometimes call codejail dozens of times during a single request, and I'd be concerned if each one of those has an expensive initialization process. If it's too early to ask those kinds of questions, I can definitely wait. I'm very excited that you folks are pursuing this. Thank you. |
Hi @ormsbee thanks for your comment. Not sure if you are thinking about running every codejail execution in a dedicated container created on-demand. I think @regisb tried that but as you mentioned the initialization times were not good enough for our use of case. So now we are thinking about handling codejail as a service like notes or discovery, which run independently to edx-platform, which allows us to have better control over it. You can see more about the discussion of codejai integration with tutor here overhangio/tutor#284. However we still need to think about scalability, which probably would need to be connected some how to edx-platform. The discussion is open and your opinion/feedback would be truly appreciated. |
@natabene This PR is now ready for review. Thanks for your help. |
@ericfab179 we're really interested in trying this out, in particular with the mitx-grading-library and its sample course that exercises a lot of custom-response features -- in particular exception handling. It's not clear to me how to run the service that goes with this PR. Do I have to run it in Tutor, or is there a way to run it in Devstack? |
@@ -0,0 +1,92 @@ | |||
""" | |||
Helper methods related to safe exec. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ericfab179 could we call this file remote
or remote_exec
to give a better idea of what kinds of helpers we should expect here?
"unsafely": unsafely | ||
} | ||
|
||
emsg, exception = send_safe_exec_request(data, extra_files) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we are already talking about a next version of this service that might cache the extra_files I think I'd like to raise a point here. It does not have to be blocking given that we also want this for maple so that tutor installs can use codejail.
We could call this version send_safe_exec_request_v0
and make the calling here configurable.
Then this _v0 function will be tied to the v0
url path in the remote API call.
Once we start upgrading the service and the call here to use v1 with the cache and whatnot we dont need to necessarily break the usage for those that do not want to install a more complicated codejail service or simply for those that need to upgrade step by step and might need to leave the v0 service running for a bit longer.
If we want to make it easy, I would say we only need to make one function signature for v0 and subsequent, for instance by adding the extra_files
to the data
dict and pass just that. Also we need to rely not only in is_codejail_rest_service_enabled() but also one function that does get_remote_exec function
that returns send_safe_exec_request_v0 for now. Once we are ready to extend we only need to extend the remote
or helpers
module to add support for v1 while v0 will still be usable.
bd69904
to
d8f6991
Compare
@felipemontoya I tried to address your comments could you please check the PR. Also I tested it again and built new images. I tried to test with master but I was having problems when creating users related to lang_pref. So I decided to back-port the changes to lilac (here is the branch that I used https://github.com/eduNEXT/edx-platform/tree/ednx/lilac-codejailservice). It is working as expected I also solved some problems that I found during the testing.
I used Tutor v12.1.3 and you can follow same instructions as given here https://github.com/edx/edx-platform/pull/27795#issuecomment-904795672 |
d8f6991
to
fee6761
Compare
Thanks a lot @ericfab179. With the latest round of changes it looks great for me too. I did not quite understand why you had to backport it to lilac. Was it only to be able to build tutor images to test? If so, then that should not be a blocker for merging. |
@ericfab179 you only need to solve the quality error: common/lib/capa/capa/safe_exec/remote_exec.py:37: [C0116(missing-function-docstring), get_remote_exec] Missing function or method docstring And we should be ready with this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like what I see here in this PR. It's simple and straight to the point. My only comment would concern the lack of documentation for the CODE_JAIL_*
settings -- as you know I'm a big fan of documenting stuff in Open edX. But my comment should probably not be a blocker for this PR.
Add codejail service settings (endpoint and feature flag). Add conditional to allow running codejail using a REST API service when flag is enabled.
Address recommendations and fixes discussed in PR. Use similar structure to notes app. Fix errors detected in tests.
Address fixes recommended by @timmc-edx.
fee6761
to
67a8074
Compare
Address @felipemonotoya recommendations related to add versioning to safe_exec_remote functions.
nltk 3.6.3 drops support for python 3.5.
67a8074
to
2a371e8
Compare
Your PR has finished running tests. There were no failures. |
@regisb we added annotations to the settings so that it is better documented from the start. |
@ericfab179 🎉 Your pull request was merged! Please take a moment to answer a two question survey so we can improve your experience in the future. |
EdX Release Notice: This PR has been deployed to the staging environment in preparation for a release to production. |
EdX Release Notice: This PR has been deployed to the production environment. |
…ernal service using REST API.
…nal service <!-- 🍁🍁 🍁🍁🍁🍁 🍁 Note: the Maple master branch has been created. Please consider whether your change 🍁🍁🍁🍁 should also be applied to Maple. If so, make another pull request against the 🍁🍁🍁🍁 open-release/maple.master branch, or ping @nedbat for help or questions. 🍁🍁 Please give your pull request a short but descriptive title. Use conventional commits to separate and summarize commits logically: https://open-edx-proposals.readthedocs.io/en/latest/oep-0051-bp-conventional-commits.html Use this template as a guide. Omit sections that don't apply. You may link to information rather than copy it. More details about the template are at openedx/open-edx-proposals#180 (link will be updated when that document merges) --> ## Description This is a backport of https://github.com/edx/edx-platform/pull/27795. The idea of this PR is to make the external Codejail service feature available in the Maple release, which will help to integrate Codejail with the Tutor ecosystem. From openedx/wg-build-test-release#98 (comment) we can confirm the feature is working. ## Deadline "None".
Add codejail service settings (endpoint and feature flag).
Add conditional to allow running codejail using a REST API service when flag is enabled.