How to tell whether imaplib2 idle response resulted from timeout - python

I'm using imaplib2 (docs) to interact with an IMAP server.
I'm using the idle command, with a timeout and a callback.
The problem is, I don't see any way of telling if the callback was triggered by the timeout being reached, or if there was a change on the server that I need to check out.
I just get ('OK', ['IDLE terminated (Success)']) every time.
Here's the debug output for both cases:
Timedout:
15:43.94 MainThread server IDLE started, timeout in 5.00 secs
15:48.94 imap.gmail.com handler server IDLE timedout
15:48.94 imap.gmail.com handler server IDLE finished
15:48.94 imap.gmail.com writer > DONE\r\n
15:49.17 imap.gmail.com reader < DDDM6 OK IDLE terminated (Success)\r\n
15:49.17 imap.gmail.com handler _request_pop(DDDM6, ('OK', ['IDLE terminated (Success)']))
Something happened:
18:41.34 MainThread server IDLE started, timeout in 50.00 secs
19:01.35 imap.gmail.com reader < * 1 EXISTS\r\n
19:01.37 imap.gmail.com handler server IDLE finished
19:01.37 imap.gmail.com writer > DONE\r\n
19:01.59 imap.gmail.com reader < BFCN6 OK IDLE terminated (Success)\r\n
19:01.59 imap.gmail.com handler _request_pop(BFCN6, ('OK', ['IDLE terminated (Success)']))
What am I missing?
Does the functionality just not exist in imaplib2?

Piers Lauder (author of imaplib2) just answered this question on the imaplib2-devel mailing list. He said:
I think the way to test if an IDLE has timed out is to execute:
instance.response('IDLE')
which will return:
('IDLE', ['TIMEOUT'])
if the reason that the idle returned as a timeout, rather than
something else (such as ('IDLE', [None])).
I agree that this should be documented, so I'll fix the imaplib2.html
document

You'll have to manually check for new messages each time you get this response. You can store the UIDs of messages in a list and compare new UIDs with it upon each callback. This way you can easily tell if there are new messages or a timeout.

Related

Python threading.Timer function doesn't wait 'n' seconds before raise exception

I'm trying to figure out why timer doesn't wait 300 secs, but raise imediately exception. Anybody can help me to resolve this issue? thanks.
here's my code:
import sys
import os
from java.lang import System
import getopt
import time as systime
from threading import Timer
import time
[...]
def _startServer(ServerName):
cd('domainRuntime:/ServerLifeCycleRuntimes/'+ServerName);
state=_serverstatus(ServerName);
while (state!='RUNNING'):
try:
cmo.start();
while (state!='RUNNING'):
state=_serverstatus(ServerName);
java.lang.Thread.sleep(1000);
t = threading.Timer(300.0,timeout)
t.start()
except:
print 'Error in getting current status of ' +ServerName+ '\n';
print 'Please check logged in user has full access to complete the start operation on ' +ServerName+ '\n';
print 'Timeout, NodeManager may be down. Checking... ' + '\n';
os.popen('sh /home/oracle/scripts/logAnalytics.sh')
systime.sleep(60)
state=_serverstatus(ServerName);
[...]
and the result:
Initializing WebLogic Scripting Tool (WLST) ...
Welcome to WebLogic Server Administration Scripting Shell
Type help() for help on available commands
172.31.129.68:7001
Connecting to t3://172.31.129.68:7001 with userid weblogic ...
Successfully connected to Admin Server 'AdminServer' that belongs to domain 'cll5_domain'.
Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.
Successfully connected to the domain
Location changed to domainRuntime tree. This is a read-only tree with DomainMBean as the root.
For more help, use help(domainRuntime)
Server Server_2 is :SHUTDOWN
Trying To Start Server:Server_2...
Server Server_2 is :SHUTDOWN
Server Server_2 is :SHUTDOWN
Error in getting current status of Server_2
Please check logged in user has full access to complete the start operation on Server_2
Timeout, NodeManager may be down. Checking...
Server Server_2 is :SHUTDOWN
Server Server_2 is :SHUTDOWN
Error in getting current status of Server_2
Please check logged in user has full access to complete the start operation on Server_2
Timeout, NodeManager may be down. Checking...
Server Server_2 is :RUNNING
Disconnected from weblogic server: AdminServer
Exiting WebLogic Scripting Tool.
(Note that the string "Server Server_2 is :SHUTDOWN" must be written on screen several times before the next process start. About 60 times, because there's a while cycle that print the string of server status every 5 secs and the timer is 300 secs.)
Environment: Oracle Linux 6, Oracle Weblogic 11
Any help is apreciated.

View processes not stopped when streaming with python flask

I use a simple Flask application with gunicorn's gevent worker to serve server-sent events.
To stream the content, i use:
response = Response(eventstream(), mimetype="text/event-stream")
which streams events from redis:
def eventstream():
for message in pubsub.listen():
# ...
yield str(event)
deployed with:
gunicorn -k gevent -b 127.0.0.1:50008 flaskapplication
But after its used for a while, i have 50 redis connections open, even when no one is connected to the server-sent events stream anymore.
It seems, like the view does not terminate, because gunicorn is non-blocking and pubsub.listen() is blocking.
How can i fix this? Should i limit the number of processes gunicorn may spawn, or should flask kill the view after some timeout? If possible, it should stop the view/redis connections on inactivity, without disconnecting users, who are still connected to the SSE stream.
You can run gunicorn with -t <seconds> to specify a timeout for your workers which will kill them if they are silent for a number of seconds, usually 30 is typical. I think this should work for your issue, but not completely sure.
From what I've seen, it seems like you could also rewrite your worker to use Timeout from gevent.
This might look something like the following:
from gevent import Timeout
def eventstream():
pubsub = redis.pubsub()
try:
with Timeout(30) as timeout:
pubsub.subscribe(channel)
for message in pubsub.listen():
# ...
yield str(event)
except Timeout, t:
if t is not timeout:
raise
else:
pubsub.unsubscribe(channel)
This example was helpful for getting a hang of how this should work.
Using the Timeout object from natdempk's solution, the most elegant solution is to send a heartbeat, to detect dead connections:
while True:
pubsub = redis.pubsub()
try:
with Timeout(30) as timeout:
for message in pubsub.listen():
# ...
yield str(event)
timeout.cancel()
timeout.start()
except Timeout, t:
if t is not timeout:
raise
else:
yield ":\n\n" # heartbeat
Note that you need to call redis.pubsub() again, because the redis connection is lost after the exception and you will get an error NoneType object has no attribute readline.

Celery Closes Unexpectedly After Longer Inactivity

So I am using a RabbitMQ + Celery to create a simple RPC architecture. I have one RabbitMQ message broker and one remote worker which runs Celery deamon.
There is a third server which exposes a thin RESTful API. When it receives HTTP request, it sends a task to the remote worker, waits for response and returns a response.
This works great most of the time. However I have notices that after a longer inactivity (say 5 minutes of no incoming requests), the Celery worker behaves strangely. First 3 tasks received after a longer inactivity return this error:
exchange.declare: connection closed unexpectedly
After three erroneous tasks it works again. If there are not tasks for longer period of time, the same thing happens. Any idea?
My init script for the Celery worker:
# description "Celery worker using sync broker"
console log
start on runlevel [2345]
stop on runlevel [!2345]
setuid richard
setgid richard
script
chdir /usr/local/myproject/myproject
exec /usr/local/myproject/venv/bin/celery worker -n celery_worker_deamon.%h -A proj.sync_celery -Q sync_queue -l info --autoscale=10,3 --autoreload --purge
end script
respawn
My celery config:
# Synchronous blocking tasks
BROKER_URL_SYNC = 'amqp://guest:guest#localhost:5672//'
# Asynchronous non blocking tasks
BROKER_URL_ASYNC = 'amqp://guest:guest#localhost:5672//'
#: Only add pickle to this list if your broker is secured
#: from unwanted access (see userguide/security.html)
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'
CELERY_ENABLE_UTC = True
CELERY_BACKEND = 'amqp'
# http://docs.celeryproject.org/en/latest/userguide/tasks.html#disable-rate-limits-if-they-re-not-used
CELERY_DISABLE_RATE_LIMITS = True
# http://docs.celeryproject.org/en/latest/userguide/routing.html
CELERY_DEFAULT_QUEUE = 'sync_queue'
CELERY_DEFAULT_EXCHANGE = "tasks"
CELERY_DEFAULT_EXCHANGE_TYPE = "topic"
CELERY_DEFAULT_ROUTING_KEY = "sync_task.default"
CELERY_QUEUES = {
'sync_queue': {
'binding_key':'sync_task.#',
},
'async_queue': {
'binding_key':'async_task.#',
},
}
Any ideas?
EDIT:
Ok, now it appears to happen randomly. I noticed this in RabbitMQ logs:
=WARNING REPORT==== 6-Jan-2014::17:31:54 ===
closing AMQP connection <0.295.0> (some_ip_address:36842 -> some_ip_address:5672):
connection_closed_abruptly
Is your RabbitMQ server or your Celery worker behind a load balancer by any chance? If yes, then the load balancer is closing the TCP connection after some period of inactivity. In which case, you will have to enable heartbeat from the client (worker) side. If you do, I would not recommend using the pure Python amqp lib for this. Instead, replace it with librabbitmq.
The connection_closed_abruptly is caused when clients disconnecting without the proper AMQP shutdown protocol:
channel.close(...)
Request a channel close.
This method indicates that the sender wants to close the channel.
This may be due to internal conditions (e.g. a forced shut-down) or due to
an error handling a specific method, i.e. an exception.
When a close is due to an exception, the sender provides the class and method id of
the method which caused the exception.
After sending this method, any received methods except Close and Close-OK MUST be discarded. The response to receiving a Close after sending Close must be to send Close-Ok.
channel.close-ok():
Confirm a channel close.
This method confirms a Channel.Close method and tells the recipient
that it is safe to release resources for the channel.
A peer that detects a socket closure without having received a
Channel.Close-Ok handshake method SHOULD log the error.
Here is an issue about that.
Can you set your custom configuration for BROKER_HEARTBEAT and BROKER_HEARTBEAT_CHECKRATE and check again, for example:
BROKER_HEARTBEAT = 10
BROKER_HEARTBEAT_CHECKRATE = 2.0

How to stop a Flask server running gevent-socketio

I have a flask application running with gevent-socketio that I create this way:
server = SocketIOServer(('localhost', 2345), app, resource='socket.io')
gevent.spawn(send_queued_messages_loop, server)
server.serve_forever()
I launch send_queued_messages_loop in a gevent thread that keeps on polling on a gevent.Queue where my program stores data to send it to the socket.io connected clients
I tried different approaches to stop the server (such as using sys.exit) either from the socket.io handler (when the client sends a socket.io message) or from a normal route (when the client makes a request to /shutdown) but in any case, sys.exit seems to fail because of the presence of greenlets.
I tried to call gevent.shutdown() first, but this does not seem to change anything
What would be the proper way to shutdown the server?
Instead of using serve_forever() create a gevent.event.Event and wait for it. To actually initiate shutdown, trigger the event using its set() method:
from gevent.event import Event
stopper = Event()
server = SocketIOServer(('localhost', 2345), app, resource='socket.io')
server.start()
gevent.spawn(send_queued_messages_loop)
try:
stopper.wait()
except KeyboardInterrupt:
print
No matter from where you now want to terminate your process - all you need to do is calling stopper.set().
The try..except is not really necessary but I prefer not getting a stacktrace on a clean CTRL-C exit.

Python: How to shutdown a threaded HTTP server with persistent connections (how to kill readline() from another thread)?

I'm using python2.6 with HTTPServer and the ThreadingMixIn, which will handle each request in a separate thread. I'm also using HTTP1.1 persistent connections ('Connection: keep-alive'), so neither the server or client will close a connection after a request.
Here's roughly what the request handler looks like
request, client_address = sock.accept()
rfile = request.makefile('rb', rbufsize)
wfile = request.makefile('wb', wbufsize)
global server_stopping
while not server_stopping:
request_line = rfile.readline() # 'GET / HTTP/1.1'
# etc - parse the full request, write to wfile with server response, etc
wfile.close()
rfile.close()
request.close()
The problem is that if I stop the server, there will still be a few threads waiting on rfile.readline().
I would put a select([rfile, closefile], [], []) above the readline() and write to closefile when I want to shutdown the server, but I don't think it would work on windows because select only works with sockets.
My other idea is to keep track of all the running requests and rfile.close() but I get Broken pipe errors.
Ideas?
You're almost there—the correct approach is to call rfile.close() and to catch the broken pipe errors and exit your loop when that happens.
If you set daemon_threads to true in your HTTPServer subclass, the activity of the threads will not prevent the server from exiting.
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
You could work around the Windows problem by making closefile a socket, too -- after all, since it's presumably something that's opened by your main thread, it's up to you to decide whether to open it as a socket or a file;-).

Categories