HTTP-сервер просто перестает отвечать - PullRequest
0 голосов
/ 05 августа 2020

Ранее я писал многопоточный веб-сервер , который иногда просто останавливал обработку запросов, а также прерывался в часы пик.

Я реализовал такую ​​же обработку на основе opencv в Python Сервер на основе Websocket, который работает нормально.

Для очень старых браузеров мне также нужна обработка на основе POST с использованием веб-сервера. Я преобразовал многопоточность в однопоточную, но это также останавливает в разное время и не печатает никаких журналов и т.д. c.

Я проверил syslog, но не догадался. Прошло больше недели, но решения не было найдено. Я подозреваю, что что-то связано с Digital Ocean VPS или сетью.

У меня есть этот код, и я не могу понять, почему он должен перестать отвечать:

from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
import cgi
import tempfile
import resource
import base64
from common import *
from datetime import datetime

print( datetime.now());

gg_hashmap = getHash()

USE_HTTPS = True

def dump(obj):
  for attr in dir(obj):
    print("obj.%s = %r" % (attr, getattr(obj, attr)))

class PostHandler(BaseHTTPRequestHandler):
        def handle(self):
            try:
                BaseHTTPRequestHandler.handle(self)
            except :
                pass

        def do_POST(self):
            try:
          
                print("new req="+str( datetime.now()),flush=True);

                form = cgi.FieldStorage(
                    fp=self.rfile,
                    headers=self.headers,
                    environ={'REQUEST_METHOD': 'POST',
                             'CONTENT_TYPE': self.headers['Content-Type'],
                             })

                
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.send_header("Access-Control-Allow-Origin", "*")
                
                self.end_headers()


              

                for field in form.keys():
                    field_item = form[field]
                    if field_item.filename:
                        
                        file_data = field_item.file.read()
                        file_len = len(file_data)
                        del file_data
                        self.wfile.write('\tUploaded %s as "%s" (%d bytes)\n' % \
                                         (field, field_item.filename, file_len))
                    else:
                        pass
                        

                if ('base64' in form and 'license' in form):
                    print("license=",form['license'].value);

                    global gg_hashmap

                    file_content = form['base64'].value
                    try:
                        
                        f, temp_file_path = tempfile.mkstemp(prefix='sand', suffix='jpg')
                        os.close(f)
                        with open(temp_file_path, 'wb') as w:
                            w.write(base64.b64decode (file_content))

                        input_hashes = get_input_img(temp_file_path)

                        all_letters = ""
                        if input_hashes != None:

                            for inp_hash in input_hashes:

                                lowest = 1000
                                lowest_letter = ''
                                for letter, arr in gg_hashmap.items():

                                    for hashval in arr:

                                        if int(inp_hash - hashval) < lowest:

                                            lowest = int(inp_hash - hashval)
                                            lowest_letter = letter
                                
                                all_letters += lowest_letter

                        self.wfile.write(bytes(all_letters, "utf8"))

                    except Exception as e:
                        print("exception3 caught")
                        print(e)
                        print(str(e))
                return
            except Exception as e:
                print("Caught unknown exception",e)
             

        def do_GET(self):
            
            self.send_response(200)
            self.end_headers()
            message =  threading.currentThread().getName()
            self.wfile.write(bytes(message,'utf-8'))
            self.wfile.write('\n')
            return


            form = cgi.FieldStorage(
                fp=self.rfile,
                headers=self.headers,
                environ={'REQUEST_METHOD': 'POST',
                         'CONTENT_TYPE': self.headers['Content-Type'],
                         })

           
            self.send_response(200)
            self.end_headers()
        
            for field in form.keys():
                field_item = form[field]
                if field_item.filename:
                    
                    file_data = field_item.file.read()
                    file_len = len(file_data)
                    del file_data
                    self.wfile.write('\tUploaded %s as "%s" (%d bytes)\n' % \
                                     (field, field_item.filename, file_len))
                else:
                    pass
                   

            return



def run():
   # resource.setrlimit(resource.RLIMIT_STACK, (2**29,-1))
   # threading.stack_size(24*1048576)
    server = HTTPServer(('0.0.0.0', 443), PostHandler)
    if USE_HTTPS:
        import ssl
        server.socket = ssl.wrap_socket(server.socket, keyfile='./ssl/key.pem', certfile='./ssl/public.pem'
                , ca_certs="./ssl/cap1_transactionfailed_com.ca-bundle" , server_side=True)

    server.serve_forever()


if __name__ == '__main__':
    run()

Ответы [ 2 ]

0 голосов
/ 05 августа 2020

С помощью mkstemp вы должны удалить временный файл. Вероятно, у вас закончилось место на диске или файлы во временном каталоге закончились. Как упоминалось в AKX, вам следует подумать об использовании более надежного HTTP-сервера. если проблема с файлом не является вашей проблемой, существует множество других проблем, которые могут возникнуть при использовании непроизводственного HTTP-сервера.

0 голосов
/ 05 августа 2020

Я не думаю, что кто-то захочет прочитать все 157 строк запутанного кода обработки HTTP-запросов (из которых некоторые даже не опубликованы, from common import *), чтобы попытаться расшифровать, почему он может остановиться в какой-то момент .

Скорее всего, это не тот ответ, который вы хотите услышать, но HTTPServer на самом деле не то, что кто-то использует в продакшене для Python.

Вы должны посмотреть переписать код с помощью одного из (моих рекомендаций на момент написания)

  • FastAPI (или его базового Starlette framework) на Uvicorn (Uvicorn позволит вам выполнять работу с веб-сокетами в том же процессе) или
  • Flask на Gunicorn или uWSGI

Например, вот приблизительная оценка того, как ваш код будет выглядеть со Starlette. (Могут быть ошибки, так как он закодирован dry, и это, конечно, не полностью асинхронный c, но здесь это не имеет значения.)

import tempfile
import base64
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import PlainTextResponse

app = Starlette()


def get_all_letters(input_hashes):
    all_letters = ""
    if input_hashes:
        for inp_hash in input_hashes:
            lowest = 1000
            lowest_letter = ""
            for letter, arr in gg_hashmap.items():
                for hashval in arr:
                    if int(inp_hash - hashval) < lowest:
                        lowest = int(inp_hash - hashval)
                        lowest_letter = letter
            all_letters += lowest_letter
    return all_letters


@app.route("/", methods=["GET", "POST"])
async def handle(request: Request):
    if request.method == "GET":
        return PlainTextResponse("Hello!")
    form = await request.form()

    if not ("base64" in form and "license" in form):
        return PlainTextResponse("Missing data!", status_code=400)
    with tempfile.NamedTemporaryFile(prefix="sand", suffix="jpg") as f:
        content = await form["base64"].read()
        f.write(base64.b64decode(content))
        f.flush()
        input_hashes = get_input_img(f)
    if not input_hashes:
        return PlainTextResponse("No input hashes!", status_code=400)
    all_letters = get_all_letters(input_hashes)
    return PlainTextResponse(all_letters)

Затем вы можете запустить это с помощью Uvicorn (который также будет обрабатывать все эти HTTPS-файлы за вас).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...