-
You must be signed in to change notification settings -
Improvements to HTTP APIs #137
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
Conversation
GlobalSharedSession allows all HTTP APIs that are children of APIRequest to share the same HTTP session. - Add support for shared_client (replace keep_session_open with this one) to APIRequest - Add is_global_shared_session_user to APIRequest - Return NotImplemented or None for close methods
FixedAsyncEndpoint and FixedAsyncEndpoint now truly share the same session. - Return Optional[type(NotImplemented)] for close methods
GlobalSharedSession is now used throughout elAPI commands.
They are mainly for elapi/api methods for now. - Rename missing_warning to preventive_missing_warning - Move preventive_missing_warning to configurations/_overload_history.py as it makes more sense to have it there as part of the simple multi-layered design pattern hierarchy (I should start using an acronym for that). - Use RuntimeWarning as superclass of PreventiveWarning - Add imports
- Replace missing_warning with preventive_missing_warning - Use update_kwargs_with_defaults to update kwargs of GlobalSharedSession and APIRequest - Reset GlobalSharedSession._instance while closing GlobalSharedSession - Make __enter__ and __exit__ instance methods from class methods - Add suppress_override_warning - Only show override warning while GlobalSharedSession is in use if certain conditions are met - Replace property with cached_property - Only update kwargs under APIRequest __init__, pass kwargs from inheriting classes as is without modification - Add imports
- Do not call SimpleClient (i.e., open connection) when GlobalSharedSession._instance is not None - Fix delete method of FixedAsyncEndpoint - Return NotImplemented for close when GlobalSharedSession._instance is not None
It seems GlobalSharedSession breaks tenacity.retry for teams-info (get_teams function). elAPI just quits after the 2nd retry, and the 1st retry doesn't do anything besides immediately triggering the 2nd retry. Either it's an issue with tenacity, or how event loop is handled/closed in RecursiveInformation. This issue is not observed when no retry is triggered (i.e., no network error). For now, we just don't use GlobalSharedSession for teams-info/get_teams.
GlobalSharedSession (GSS) throws RuntimeError if the event loop closes abruptly before its close method can run. This fixes the issue in commit 0fa1fae.
The issue is fixed in commit 0fa1fae.
A few updatesSince the merge, a few commits related to this PR has been made to
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
improvement
new-feature
plugin-bill-teams
Issues and PRs related to bill-teams plugin. bill-teams is an internal plugin.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR mainly brings improvements that shaves off 1-2 seconds (!) of heavy-duty plugins like
bill-teams
andexperiments
.Shared clients
elAPI provides the following core APIs that can be imported from
elapi.api
that do the heavy lifting of all HTTP calls to eLabFTW without having to worry about configuring HTTP client and make working with eLab API responses convenient.GETRequest
POSTRequest
PATCHRequest
DELETERequest
AsyncGETRequest
AsyncPOSTRequest
AsyncPATCHRequest
AsyncDELETERequest
Each one of them by default opens a connection once, and closes it immediately after one HTTP request. This is useful when we only need a single request (e.g.,
elapi get <endpoint name>
command) and don't want to worry about forgetting to close the request.This immediate closing of connection can soon become very limiting as we need to make repeated requests. A
keep_session_open
keyword argument was introduced before.Not only
keep_session_open
would open individual connections for eachGET
,POST
,PATCH
andDELETE
, we would also need to make sure to close them manually. We deprecatekeep_session_open
in this PR, and introduceSimpleClient
and the replacement ofkeep_session_open
,shared_client
.This eases sharing the same client when needed.
SimpleClient
also just returns ahttpx.Client
orhttpx.AsyncClient
depending on the value of keyword argumentis_async_client
. So it can also be used in wayshttpx.Client
/httpx.AsyncClient
can be used. I.e.,SimpleClient
can also be used as context manager.With context manager, we need not to worry about closing the connections, as they are closed when context manager is automatically.
This solution still inherits one big problem. All existing code that does not use
shared_client
argument will now need to be updated. In the next section, we will introduce a solution to that.GlobalSharedSession
In the following example, we pseudo-code a script that uses a number of aforementioned elAPI HTTP APIs and runs some advanced automation task.
Since each function makes calls to one or more of
GET
,POST
,PATCH
andDELETE
, this script would be perfect use-case ofshared_client
. But that would require updating the code of all 5 functions. In this PR, we introduceGlobalSharedSession
that lets us avoid just that using the power of OOP (although the user doesn't need to deal with any OOP). Themain
function can use a single connection to make all requests in the following way:The change in one line will now force all elAPI HTTP APIs to use a single connection (internally, of course, its using HTTPX connection pooling) and automatically closes it accordingly.
GlobalSharedSession
has been added to all elAPI CLI commands.GlobalSharedSession
benchmarkWe already mentioned in the introduction that
GlobalSharedSession
trims a mere 1-2 seconds. That is the case when we're making a single or a few eLab API calls. We usehyperfine
to run a simple benchmark ofelapi get users
targeting serverdev-002
(with more than 2500+ users). Here,~/.local/bin/elapi
is not usingGlobalSharedSession
, andelapi
command is.This is not a significant improvement and the final number (1.17x) fluctuates a lot.
Where
GlobalSharedSession
truly makes a big difference is when we run HTTP APIs withoutshared_client
, i.e., when we do not update existing code. Let's benchmark an example that reflects that. The following benchmark compares the speed of 10-times repeatingGET
(not async) requests to endpointinfo
in a loop between with-GlobalSharedSession
and without.~/.local/bin/elapi awesome repeated-get-requests info
elapi awesome repeated-get-requests info
with GlobalSharedSession(): for _ in range(10): validate = Validate(HostIdentityValidator(), PermissionValidator(group="sysadmin")) validate() r = GETRequest() print(f'Request {_}: {r(endpoint_name)}')
for _ in range(10): validate = Validate(HostIdentityValidator(), PermissionValidator(group="sysadmin")) validate() r = GETRequest() print(f'Request {_}: {r(endpoint_name)}')
Running
hyperfine
:The for loop making
GETRequest()
calls and some more calls for permission validation, is almost 2x faster withGlobalSharedSession
.GlobalSharedSession
gotchasGlobalSharedSession
will override any and all arguments passed to elAPI HTTP APIs. This can be undesirable if the user is doing something specific with one of the API classes.GlobalSharedSession
will show warning log for when it is necessarily overriding such arguments.GlobalSharedSession
will open two connections only one for sync connection and another for async connection. If we only want to work with sync connections, we should useGlobalSharedSession(limited_to="sync")
, andGlobalSharedSession
will not open or override any of the async HTTP APIs.limited_to
can acceptsync
orasync
orall
(default isall
).nest-asyncio
forGlobalSharedSession
to properly work.GlobalSharedSession
can be used as a normal class as well instead of using it as a context manager. In which case, the session must be closed manually. Though, using it as a context manager is more recommended.GlobalSharedSession
can be used multiple times. Each time a new connection will be opened after closing the previous connection (if GSS is used as a context manager). Though, this is intended and not a gotcha.