Thanks. I'll try your suggestion.
On Thu, Aug 9, 2018 at 8:03 PM, Graham Dumpleton <[email protected]
> wrote:
> For a start, you should be doing something like:
>
> try:
> context = zmq.Context()
> #print "Connecting to server..." - commented out based on your
> answer
> socket = context.socket(zmq.DEALER)
> socket.connect ("ipc://%s" % ipc_sock)
>
> try:
>
> # socket.setsockopt(zmq.SOCKOPT_LINGER, 0) this should be the
> default for close() and is not in python binding
> poll = zmq.Poller()
> poll.register(socket, zmq.POLLIN)
>
> socket.send_string (send_msg)
> socks = dict(poll.poll(REQUEST_TIMEOUT))
>
> if socket in socks and socks[socket] == zmq.POLLIN:
> reply_msg = socket.recv()
> if '"Error":' not in reply_msg:
> cur_ms = time.time()
> elapsed_ms = cur_ms - start_ms
> reply_msg = '{"Data": ' + reply_msg + ',"Resp_time": "' +
> str(elapsed_ms) + '"}'
> else:
> reply_msg = '{"Error": "No Response from CMDSRV in ' +
> str(REQUEST_TIMEOUT) + ' milliseconds"' + alert_param
>
> socket.setsockopt(zmq.LINGER, 0)
>
> finally:
> socket.close()
> try:
> poll.unregister(socket)
> except Exception:
> pass
>
>
> except Exception as e:
> reply_msg = '{"Error": "' + e.message + '"' + alert_param
>
> This way if an error occurs and exception passed back, that you ensure you
> close the socket promptly, and potentially deregister it from the poller if
> necessary.
>
> If don't do that for errors, socket may stay open.
>
> Graham
>
> On 10 Aug 2018, at 9:58 am, Tim Moody <[email protected]> wrote:
>
> If it is not an imposition here is the entire app:
>
> import zmq
> import os.path
> import time
> import urllib2
>
> cmdsrv_pid_file = "{{ cmdsrv_pid_file }}"
> cmdsrv_ready_file = "{{ cmdsrv_ready_file }}"
>
> alert_param = ',"Alert": "True"}'
>
> def application(environ, start_response):
> start_ms = time.time()
>
> if environ['REQUEST_METHOD'] == 'POST':
> try:
> request_body_size = int(environ.get('CONTENT_LENGTH', 0))
> except (ValueError):
> request_body_size = 0
>
> request_body = environ['wsgi.input'].read(request_body_size)
> # request_body holds command=<text of cmd>
>
> if os.path.exists(cmdsrv_pid_file):
> if os.path.exists(cmdsrv_ready_file):
> # unpack cmd, urldecode, and substitute space for %20
> cmd = urllib2.unquote(request_body.
> split('=')[1]).decode('utf8')
> cmd = cmd.replace('%20', ' ')
>
> response_body = send_command(cmd, start_ms)
> else:
> response_body = '{"Error": "CMDSRV has started but is not
> ready."' + alert_param
> else:
> response_body = '{"Error": "CMDSRV is not running."' +
> alert_param
>
> response_headers = [('Content-type', 'application/json'),
> ('Content-Length', str(len(response_body)))]
>
> else: # not a POST
> response_body = dump(environ)
> response_headers = [('Content-type', 'text/plain'),
> ('Content-Length', str(len(response_body)))]
> status = '200 OK'
> start_response(status, response_headers)
> return [response_body]
>
> def dump(environ):
> response_body = ['%s: %s' % (key, value) for key, value in
> sorted(environ.items())]
> response_body = '\n'.join(response_body)
> return response_body
>
> def send_command(cmd, start_ms):
>
> REQUEST_TIMEOUT = 30000
> send_msg = cmd
>
> ipc_sock = "/run/cmdsrv_sock"
>
> try:
> context = zmq.Context()
> #print "Connecting to server..." - commented out based on your
> answer
> socket = context.socket(zmq.DEALER)
> socket.connect ("ipc://%s" % ipc_sock)
> # socket.setsockopt(zmq.SOCKOPT_LINGER, 0) this should be the
> default for close() and is not in python binding
> poll = zmq.Poller()
> poll.register(socket, zmq.POLLIN)
>
> socket.send_string (send_msg)
> socks = dict(poll.poll(REQUEST_TIMEOUT))
>
> if socket in socks and socks[socket] == zmq.POLLIN:
> reply_msg = socket.recv()
> if '"Error":' not in reply_msg:
> cur_ms = time.time()
> elapsed_ms = cur_ms - start_ms
> reply_msg = '{"Data": ' + reply_msg + ',"Resp_time": "' +
> str(elapsed_ms) + '"}'
> else:
> reply_msg = '{"Error": "No Response from CMDSRV in ' +
> str(REQUEST_TIMEOUT) + ' milliseconds"' + alert_param
>
> socket.setsockopt(zmq.LINGER, 0)
> socket.close()
> poll.unregister(socket)
>
> except Exception as e:
> reply_msg = '{"Error": "' + e.message + '"' + alert_param
>
> return reply_msg
>
>
> On Thu, Aug 9, 2018 at 7:48 PM, Tim Moody <[email protected]> wrote:
>
>> Well, I think it is thread safe. The mod_wsgi application is an end point
>> for an ajax request, which it forwards to the multi-threaded backend server
>> over a zeromq socket (using a linux ipc socket), polls for a response for
>> up to 30 seconds, and returns the json result or failure to the ajax
>> caller's callback function. It then terminates. All of this is password
>> protected using apache mod_auth, part of the reason I didn't just use uwsgi.
>>
>>
>> On Thu, Aug 9, 2018 at 7:30 PM, Graham Dumpleton <
>> [email protected]> wrote:
>>
>>>
>>>
>>> > On 10 Aug 2018, at 9:22 am, Tim Moody <[email protected]> wrote:
>>> >
>>> > Thanks for replying so quickly. The message is indeed a print
>>> statement in my python wrapper. It was the wsgi.error that threw me off. So
>>> I guess it is really an info message.
>>> >
>>> > However, I still get failed connections, but perhaps these are from
>>> zeromq and not from mod_wsgi. However, to be sure, I should say that I am
>>> not using WSGIDaemonProcess but only WSGIScriptAlias and all other defaults
>>> (on 4.3.0 Ubuntu 16.04). Is there any chance that mod_wsgi will be starved
>>> for connections if 8 requests arrive nearly simultaneously?
>>>
>>> Is your use of the client for backend service thread safe?
>>>
>>> A typical configuration for Apache/mod_wsgi means that you have multiple
>>> threads per process handling requests, so you have to be careful to ensure
>>> that each request has own client instance, or if one client instance that
>>> can handle multithread access okay.
>>>
>>> Anyway, how many concurrent requests mod_wsgi can handle for embedded
>>> mode is dictated by Apache MPM settings. This is unrelated though to
>>> backend connections and whether limits enforced by backend service. If
>>> capacity to handle more requests had been reached as Apache MPM settings
>>> low, requests would just queue up and never get to the application until
>>> free capacity, so not going to affect anything in backend connections for
>>> those requests which are able to be handled.
>>>
>>> Graham
>>>
>>> --
>>> You received this message because you are subscribed to a topic in the
>>> Google Groups "modwsgi" group.
>>> To unsubscribe from this topic, visit https://groups.google.com/d/to
>>> pic/modwsgi/HMKpmmNacX4/unsubscribe.
>>> To unsubscribe from this group and all its topics, send an email to
>>> [email protected].
>>> To post to this group, send email to [email protected].
>>> Visit this group at https://groups.google.com/group/modwsgi.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "modwsgi" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at https://groups.google.com/group/modwsgi.
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "modwsgi" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/
> topic/modwsgi/HMKpmmNacX4/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> [email protected].
> To post to this group, send email to [email protected].
> Visit this group at https://groups.google.com/group/modwsgi.
> For more options, visit https://groups.google.com/d/optout.
>
--
You received this message because you are subscribed to the Google Groups
"modwsgi" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/modwsgi.
For more options, visit https://groups.google.com/d/optout.