Apache在输入套接字上超时

时间:2017-10-21 13:16:24

标签: python apache flask

我正在使用Python的Flask模块并通过apache2 httpd的WSGI模块运行它。配置如下所示。

httpd.conf:
...
WSGISocketPrefix <somedir>/wsgisock
include sites-enabled

然后在我的python代码中,我以这种方式调用Flask:

from flask import Flask, jsonify, abort, request

我的python程序接收有效负载,作为响应,执行长任务,通常需要超过30分钟。最后它返回一个响应主体。但是,那时我在错误输出文件中看到了这条消息:

[reqtimeout:info] [pid 7036] [client xxx.xx.xxx.xx:37038] AH01382: Request body read timeout

我在httpd进程上运行strace并发现:

brk(NULL)                               = 0x7fd2b961a000
brk(0x7fd2b963b000)                     = 0x7fd2b963b000
write(6, "[Sat Oct 21 15:02:21.771995 2017"..., 127) = 127
writev(10, [{"HTTP/1.1 201 CREATED\r\nDate: Sat,"..., 257}, {"{\n  
\"outcomeDetails\": \"Successfu"..., 2873}, {"", 0}], 3) = 3130
write(8, "xxx.xx.xxx.xx - - [21/Oct/2017:1"..., 183) = 183
times({tms_utime=0, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 714623894
close(11)                               = 0
shutdown(10, SHUT_WR)                   = 0
poll([{fd=10, events=POLLIN}], 1, 2000) = 0 (Timeout)
close(10)                               = 0
read(4, 0x7fff5156c92f, 1)              = -1 EAGAIN (Resource temporarily 
unavailable)
accept4(3,

很明显,httpd进程确实写入了套接字。但是,我没有看到任何客户端(Java servlet)。任何人都知道如何解决这个问题?

这是我的python代码:

#!usr/bin/python
from flask import Flask, jsonify, abort, request
import threading, myClass, time, inspect, sys, pprint, os

app = Flask(__name__)

# Dictionary to store threadname, output and returnvalue of task being executed

threads_n_outputs = {'task_string' : {'threadName' : 'thread1', 'logFile' : 'logFile', 'executionResult' : {}}} 

tasks = {
    'myTask1': {
        'Description': u'blah blah', 
    'inputParams': {'var1': u'','var2': u''},
    'outputParams': {'taskOutcome': u'', 'outcomeDetails': u'', 'reversePayload': {}}
    },
    'myTask2': {
        'Description': u'blah blah blah',
    'inputParams': {'var1': u'','var2': u''},
    'outputParams': {'taskOutcome': u'', 'outcomeDetails': u'', 'reversePayload': {}}
    }
}


@app.route('/some/path')
def get_tasks():
    return jsonify(tasks)

# Get method to list specific tasks 

@app.route('/some/path/<task_name>')
def get_task(task_name):
    if tasks[task_name]:
        return jsonify(tasks[task_name])
    else:
    abort(404)

# Get method to show status of a running task

@app.route('/some/path/status/<task_string>')
def showStatus(task_string):
    global threads_n_outputs
    if task_string == 'allRunningJobs':     # Show all running jobs
    temp_dict = dict(threads_n_outputs)
    del temp_dict['task_string']
    if temp_dict:
        return jsonify(temp_dict.keys())
    else:
        return 'No running jobs as of now.'
    if task_string in threads_n_outputs:    # show status for specific job
    with open(threads_n_outputs[task_string]['logFile'], 'r') as fileHandle:
            return jsonify(fileHandle.read().splitlines())
    else:
    return 'No running job named ' + task_string + ' as of now.'

class runTaskClass(threading.Thread):
    global threads_n_outputs
    def __init__(self, functionName, kwargs, task_string, logFile):
        super(runTaskClass, self).__init__(name = task_string)
        self.functionName = functionName 
        self.kwargs = kwargs
    self.task_string = task_string
    self.logFile = logFile 

    def run(self):
    try:
        # Write to logfile instead of stdout
        with open(self.logFile, "w", 1) as fileHandle: 
                with fileHandle as sys.stdout:
                    print '\n' + 'Starting ' + self.task_string + ' at ' + str(time.ctime()) + '\n'
                    threads_n_outputs[self.task_string]['executionResult'] = self.functionName(**self.kwargs)
                    print '\n' + 'Task ' + self.task_string + ' completed at ' + str(time.ctime()) + '\n'
            sys.stdout = sys.__stdout__ # Reset stdout to normal
    except Exception, inst:
        fileHandle.close()      # Close file if exception occured within 'with' statement
        sys.stdout = sys.__stdout__ # Reset stdout to normal
            print '\n' + 'runTaskClass : Error While running ' + str(self.task_string) + ' - ' + str(inst)

# Post method to execute a task

@app.route('/some/path/<task_string>', methods=['POST'])    ## task_string comprises of taskname and querytstring to get status of task
def execute_task(task_string):
    print request.get_data()        # print raw input data
    sys.stdout.flush()

    requestData = request.get_json()

    if not requestData: 
    print '\n' + 'ERROR : Posted data is not valid' + '\n'
        abort(400)

    outputParams={'taskOutcome': u'', 'outcomeDetails': u'', 'reversePayload': {}}

    def updateOutputParams(taskOutcome, outcomeDetails, reversePayload):
    outputParams.update(dict(zip(['taskOutcome', 'outcomeDetails', 'reversePayload'],[taskOutcome, outcomeDetails, reversePayload])))
    return jsonify(outputParams), 201

    if len(task_string.split('_')) < 2:             ## If task_string is not in desired format exit with error
        return updateOutputParams('Failure','Error: task_string format should be taskname_queryString', None)

    task_name = task_string.split('_')[0]

    task_details=task_name + ' with arguments ' + ",".join(["%s=%s" % (k, v) for k, v in requestData.items()])
    print '\n' + 'Executing '+ task_details + '\n'
    task_instance=<someclass>.<someclass>() 
    task_instance.logon()
    functionName='task_instance.' + task_name
    logFile=task_instance.logDirectory + '/td_' + task_string + '.log' # logfile for this job

    if os.path.isfile(logFile):
    newlogFile = logFile + time.strftime("%d%b%Y_%Hh%Mm%Ss")
    os.rename(logFile, newlogFile)

    #Verify if task domain function named task_name exists
    try:
    if callable(eval(functionName)):
        print '\n' + 'Verified that '+ functionName +' is a valid function. Proceeding with validation of arguments.'
    else:
        return updateOutputParams('Failure', 'Error:' + functionName + ' is not a valid function.', None)
    except:
    return updateOutputParams('Failure', 'Exception:' + functionName + ' is not a valid function.', None)

    #Verify if arguments count provided for task_name function is valid

    if len(requestData.items()) + 1 == len(inspect.getargspec(eval(functionName))[0]):  # +1 for first argument 'this'
    print '\n' + 'Argument count for ' + functionName + ' is valid. Proceeding with execution of this function now.' + '\n' 
    else:
    return updateOutputParams('Failure','Error:Argument count for ' + functionName + ' does not match with definition.', None)

    #Initialize the placeholder variable for this thread

    global threads_n_outputs

    #Never start a thread if another thread with same name is running at the moment

    if task_string in threads_n_outputs:
    return updateOutputParams('Failure','Error: Job named ' + task_string + ' is already running. Please submit with distinct identifier', None)
    else:
        threads_n_outputs[task_string] = {'thread': None, 'logFile' : logFile, 'executionResult' : {}}

    #Call task_name function

    try:
    print '\n' + 'Initializing Thread for job ' + str(task_string) + ' ...'
        threads_n_outputs[task_string]['thread'] = runTaskClass(eval(functionName), requestData, task_string, logFile)
        threads_n_outputs[task_string]['thread'].start()
        threads_n_outputs[task_string]['thread'].join()
    print '\n' + 'Thread for job ' + str(task_string) + ' completed.'
        executionResult=threads_n_outputs[task_string]['executionResult']
    print '\n' + 'Execution result for Thread ' + str(task_string) + ' :'
    pprint.pprint(executionResult)

        # handle exception of executionResult['outcomeDetails'] being None when outcome of successful jobs like startVM result None object
        if executionResult['outcomeDetails'] is None:
            executionResult['outcomeDetails'] = 'None'

        outcomeDetails='Successfully executed ' + task_details + ', Outcome details = ' + executionResult['outcomeDetails'] if executionResult['taskOutcome'] == 'Success' else 'Execution failed for ' + task_details + ':Error message is - ' + executionResult['outcomeDetails']

        # Delete current thread's info from threads_n_outputs

        del threads_n_outputs[task_string]

        return updateOutputParams(executionResult['taskOutcome'], outcomeDetails, executionResult['reversePayload'])

    except Exception, inst:
    del threads_n_outputs[task_string]
    print '\n' + 'While running ' + str(task_string) + ' : ERROR ' + str(inst)
        return updateOutputParams('Failure', 'While running ' + str(task_string) + ' : ERROR ' + str(inst), None)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5011, debug=True)

0 个答案:

没有答案