Delay in receiving first message from a websocket connection - python

I am writing a code in Python to send three POST requests consecutively if certain conditions are met. The POST requests are sent to the FTX Exchange (which is a crypto exchange) and each request is a 'buy' order.
The second order is triggered as soon as the first is filled, and the third as soon as the second is filled. In order to speed up the code (I need the orders to be executed very close to each other in time), I am sending all POST requests to a subprocess (with multiprocessing.Process()) and, instead of waiting for the request response, I wait for an update from a websocket connection to the walletchannel that notifies each new filled order. This websocket connection is opened at the very beginning of the code, in a subprocess.
So, the timeline of the code is the following
Open Websocket connection to the wallet channel
Loop until conditions are met
If True, exit loop and send first order through POST request
Wait until the first order is filled (i.e. update from the websocket)
Send second order through POST request
Wait until the second order is filled (i.e. update from the websocket)
Send third order through POST request
Wait until the third order is filled (i.e. update from the websocket)
Return "Orders submitted and filled"
I have the small problem that in step (4) the update from the websocket takes too much time to arrive (of the order of 1 second), while steps (6) and (8) are pretty fast (of the order of milliseconds).
It looks like the websocket connection is somehow sleeping before the steps (3)-(4) and it takes some time to receive messages but, as soon as the first message is received, all the subsequent messages arrive very fast. I am not a network expert... how can I avoid such delay in receiving the first message from the websocket?
I am pinging the websocket connection every 20 seconds and waiting for a pong within 10 seconds.

I think it is not the problem with your code but the problem with the service that you are using.
For example, if the server is getting a simple request such as pinging, it takes very little time to process the request and respond. However, if it is a complex request such as buying crypto, it may take some time at the server to process your request, and this is what I believe creates some delay with your first request.
I think that happens with the only first request because the server has some caching that saves the recent user.

Related

Does setting socket timeout cancel the initial request

I have a request that can only run once. At times, the request takes much longer than it should.
If I were to set a default socket timeout value (using socket.setdefaulttimeout(5)), and it took longer than 5 seconds, will the original request be cancelled so it's safe to retry (see example code below)?
If not, what is the best way to cancel the original request and retry it again ensuring it never runs more than once.
import socket
from googleapiclient.discovery import build
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type
#retry(
retry=retry_if_exception_type(socket.timeout),
wait=wait_fixed(4),
stop=stop_after_attempt(3)
)
def create_file_once_only(creds, body):
service = build('drive', 'v3', credentials=creds)
file = service.files().create(body=body, fields='id').execute()
socket.setdefaulttimeout(5)
create_file_once_only(creds, body)
It's unlikely that this can be made to work as you hope. An HTTP POST (as with any other HTTP request) is implemented by sending a command to the web server, then receiving a response. The python requests library encapsulates a lot of tedious parts of that for you, but at the core, it's going to do a socket send followed by a socket recv (it may of course require more than one send or recv depending on the size of the data).
Now, if you were able to connect to the web server initially (again, this is taken care of for you by the requests library but typically only takes a few milliseconds), then it's highly likely that the data in your POST request has long since been sent. (If the data you are sending is megabytes long, it's possible that it's only been partially sent, but if it is reasonably short, it's almost certainly been sent in full.)
That in turn means that in all likelihood the server has received your entire request and is working on it or has enqueued your request to work on it eventually. In either case, even if you break the connection to the server by timing out on the recv, it's unlikely that the server will actually even notice that until it gets to the point in its execution where it would be sending its response to your request. By that point, it has probably finished doing whatever it was going to do.
In other words, your socket timeout is not going to apply to the "HTTP request" -- it applies to the underlying socket operations instead -- and almost certainly to the recv part on the tail end. And just breaking the socket connection doesn't cancel the HTTP request.
There is no reliable way to do what you want without designing a transactional protocol with the close cooperation of the HTTP server.
You could do something (with the cooperation of the HTTP server still) that could do something approximating it:
Create a unique ID (UUID or the like)
Send a request to the server that contains that UUID along with the other account info (name, password, whatever else)
The server then only creates the account if it hasn't already created an account with the same unique ID.
That way, you can request the operation multiple times, but know that it will only actually be implemented once. If asked to do the same operation a second time, the server would simply respond with "yep, already did that".

Allowing message dropping in websockets

Is there a simple method or library to allow a websocket to drop certain messages if bandwidth doesn't allow? Or any one of the following?
to measure the queue size of outgoing messages that haven't yet reached a particular client
to measure the approximate bitrate that a client has been receiving recent messages at
to measure the time that a particular write_message finished being transmitted to the client
I'm using Tornado on the server side (tornado.websocket.WebSocketHandler) and vanilla JS on the client side. In my use case it's really only important that the server realize that a client is slow and throttle its messages (or use lossier compression) when it realizes that condition.
You can implement this on top of what you have by having the client confirm every message it gets and then use that information on the server to adapt the sending of messages to each client.
This is the only way you will know which outgoing messages haven't yet reached the client, be able to approximate bitrate or figure out the time it took for the message to reach the client. You must consider that the message back to the server will also take time and that if you use timestamps on the client, they will likely not match your servers as clients have their time set incorrectly more often than not.

Get continuous response of POST request in python

I'm writing a script which does a POST request to a server and gets blocked the server keeps sending the response whenever a specific event is triggered. I have to take a cookie for post request with earlier login request and pass it as data to POST, each cookie lasts for 10 mins after which I've to run keep-alive request.
Whenever some event is triggered I want to log that event in a file, I tried async, unirest requests they generate the post request but I don't have control over output, I tried sessions also but of no use. I want to do following things in same order
1]Login (can do only once)
2]Post the request to server
3]Keep monitoring output of step 2 eternally whenever there is some output log it into a file
4]Keep the session alive by another request to server.
Let me know if you need more explanation.
Below is code, it does not work though
while True:
try:
xmldata = "<eventSubscribe cookie=\"%s\" />" % (self.cookie)
r = requests.post(post_url,data=xmldata,stream=False,verify=False,timeout=10)
write_to_file('Ok',r.text)
unsubevents()
logout()
except Exception as e:
print e
self.write_to_file('Ok',"")
self.login()
So in above code the post call I make here is blocking and continuous, It streams the output continuously so the post call never really gets completed.
But it receives output in xml format, server sends these responses every time an event is triggered.
PS: I don't want to do logout and login again,this works in curl where it keeps printing output on stdout, I have to run this code for several servers like 200.
I've fixed this problem with two level threading and reading chunks instead of content or read_lines().
1] First threads will be created which will spawn second thread and run keepalive when timeout hits.
2]Second thread subscribes to event with POST request and then keeps on listening to chunks of size 1024 everytime a response is received it is parsed and respective data is updated. Here I used requests with Stream=True; This wasn't working for me earlier because cookie used to expire before reading response and session used to close.
If someone has better way to do this please update here.

HTTP Callback URL vs. WebSocket for ansynchronous response?

I have two servers: Golang and Python (2.7). The Python (Bottle) server has a computation intensive task to perform and exposes a RESTful URI to start the execution of the process. That is, the Go server sends:
HTTP GET to myserver.com/data
The python server performs the computation and needs to inform the Go server of the completion of the processing. There are two ways in which I see this can be designed:
Go sends a callback URL/data to Python and python responds by hitting that URL. E.g:
HTTP GET | myserver.com/data | Data{callbackURI:goserver.com/process/results, Type: POST, response:"processComplete"}
Have a WebSocket based response be sent back from Python to Go.
What would be a more suitable design? Are there pros/cons of doing one over the other? Other than error conditions (server crashed etc.,) the only thing that the Python server needs to actually "inform" the client is about completing the computation. That's the only response.
The team working on the Go server is not very well versed with having a Go client based on websockets/ajax (nor do I. But I've never written a single line of Go :) #1 seems to be easier but am not aware of whether it is an accepted design approach or is it just a hack? What's the recommended way to proceed in this regard?
If you want to do it RESTful, then when the client requests HTTP GET myserver.com/data the server should return a 202 Accepted status code:
202 Accepted
The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place. There is no facility for re-sending a status code from an asynchronous operation such as this.
The 202 response is intentionally non-committal. Its purpose is to allow a server to accept a request for some other process (perhaps a batch-oriented process that is only run once per day) without requiring that the user agent's connection to the server persist until the process is completed. The entity returned with this response SHOULD include an indication of the request's current status and either a pointer to a status monitor or some estimate of when the user can expect the request to be fulfilled.
The Python server could return an ETA and an URL to a temporary resource to request the current status of the operation (e.g.: myserver.com/temp_data?processing_status). Then it's up to the Go client to wait for the task to fulfill by requesting this resource and reading the ETA. Once the processing is done, the Python server could return a 410 Gone status with the definitive URL of the new resource.
It depends on how often these signal are being sent. If it's many times per second, keeping a websocket open might make more sense. Otherwise, use option #1 since it will have less overhead and be more loosely coupled.

What happens if a HTTP connection is closed while AppEngine is still running

The real question is if Google App Engine guarantees it would complete a HTTP request even if the connection is no longer existed (such as terminated, lost Internet connection).
Says we have a python script running on Google App Engine:
db.put(status = "Outputting")
print very_very_very_long_string_like_1GB
db.put(status = "done")
If the client decides to close the connection in the middle (too much data coming...), will status = "done" be executed? Or will the instance be killed and all following code be ignored?
If the client breaks the connect, the request will continue to execute. Unless it reaches the deadline of 60 seconds.
GAE uses Pending Queue to queue up requests. If client drops connection and request is already in the queue or being executed, then it will not be aborted. Afaik all other http servres behave the same way.
This will be a real problem when you make requests that change state (PUT, POST, DELETE) on mobile networks. On Edge networks we see about 1% of large requests (uploads, ~500kb) dropped in the middle of request executing (exec takes about 1s): e.g. server gets the data and processes it, but client does not receive response, triggering it to retry. This could produce duplicate data in the DB, breaking integrity of this data.
To alleviate this you will need to make your web methods idempotent: repeating the same method with same arguments does not change state. The easiest way to achieve this would be one of:
Hash relevant data and compare to existing hashes. In you case it would be the string you are trying to save (very_very_very_long_string_like_1GB). You can do this server side.
Client provides unique request-scoped ID, and sever checks if this ID was already used.

Categories

Resources