python api通用服务,健壮性还需要优化,目前初级版本,仅供参考

重新优化了下,后续还需要继续优化日志和管道读取问题 

再次改造了下,全局变量必须独享。虽然我是以字典形式做到了保证,但感觉通用性不强

最后发现还是利用GIL来控制比较有效率,用lock反而在大量并发时效率十分低下

# -*- coding:utf-8 -*-
'''
@Project: base_service
@Auth: Louishu
@File: base_service.py
@Ide: PyCharm
@Blog: https://blog.csdn.net/louishu_hu
@Git:https://github.com/neo19850910/
@QQ: 1641143982
@Email: 1641143982@qq.com
@Time: 2019-04-10 15:23:45
'''

from wsgiref.simple_server import make_server
import os
import json
from subprocess import Popen, PIPE, STDOUT
import requests
import hashlib
from configobj import ConfigObj
import signal
from multiprocessing import Process
import threading
import time
from stdlog import *

header = {'Content-Type': 'application/json'}
pidlist = {}
processes = []
old_pidset = []
#lock = threading.Lock()

def kill_child(port):
    pid_set = os.popen ("lsof -i:%s|grep -v PID|awk '{print $2}'" % port).readlines ()
    for pid in pid_set:
        if pid != '' and pid:
            old_pidset.append (pid)


def term(sig_num, addtion):
    os.killpg (os.getpgid (os.getpid ()), signal.SIGKILL)


def md5_key(arg):
    hash = hashlib.md5 ()
    hash.update (arg)
    return hash.hexdigest ()


def callback(func):
    def wrapper(*args, **kwargs):
        # signal.signal (signal.SIGTERM, term)
        # t = Process (target=func, args=args, kwargs=kwargs)
        # t.daemon = True
        # t.start ()
        t = threading.Thread (target=func, args=args, kwargs=kwargs)
        t.start ()


    return wrapper



class rtsp (object):

    def __init__(self):
        self.log = Logger ('all.log', level='info')

    def routers(self):
        urlpatterns = (
            ('/pyservice/start', self.start),
            ('/pyservice/stop', self.stop),
            ('/pyservice/restart', self.restart),
        )
        return urlpatterns

    def start(self, environ, start_response):
        start_response ('202 OK', [('Content-Type', 'application/json')])
        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)
        _command = eval (request_body)['command']
        _serialNumber = eval (request_body)['serialNumber']
        try:
            _callBackUrl = eval (request_body)['callBackUrl']
            self.log.logger.info (u'回调地址是:{}'.format (_callBackUrl))
            self.begin (_command, _callBackUrl, _serialNumber)
        except:
            self.begin (command=_command, serialNumber=_serialNumber)
        return [json.dumps ({'code': 202})]

    @callback
    def begin(self, command, callBackUrl=None,serialNumber=None):
        if callBackUrl:
            if pidlist.has_key (md5_key (command)):
                self.log.logger.info (u'已经进入重复回调环节')
                self.log.logger.info (u'执行的命令为:{}'.format (command))
                _pid = pidlist[md5_key (command)]
                try:
                    start_time = time.time ()
                    res = requests.post (callBackUrl, json={'pid': _pid, 'result': 'success',
                                                            'remarks': 'Already publishing'})
                    self.log.logger.info (u'回调地址是:{}'.format (callBackUrl))
                    self.log.logger.info (u'执行请求耗时:{}'.format (time.time () - start_time))
                    self.log.logger.info (u'请求响应码:{}'.format (res.status_code))
                except:
                    self.log.logger.error (u'video-transcode微服务未开启或其他原因!')
            else:
                _start_result = Popen ([command], shell=True, stdout=PIPE, stderr=STDOUT)
                _pid = _start_result.pid
                buff = ''
                for i in range (20):
                    buff += _start_result.stdout.readline ()
                if 'failed' in buff:
                    requests.post (callBackUrl, json={'pid': _pid, 'result': 'fail',
                                                      'remarks': 'No route to host or other reason'})
                    self.log.logger.error (buff)

                else:
                    _pid = _start_result.pid
                    lock.acquire ()
                    pidlist[md5_key (command)] = _pid
                    lock.release ()
                    start_time = time.time ()
                    res = requests.post (callBackUrl,
                                         json={'pid': _pid, 'result': 'success', 'remarks': 'null'})
                    self.log.logger.info (u'本次请求执行命令为:{}'.format (command))
                    self.log.logger.info (u'请求响应码:{}'.format (res.status_code))
                    end_time = time.time ()
                    self.log.logger.info (u'请求耗时:{}'.format (end_time - start_time))

        else:
            self.log.logger.error (u'未传入回调地址!')

    def stop(self, environ, start_response):
        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)
        _pid = eval (request_body)['pid']
        _command = eval (request_body)['command']
        _callBackUrl = eval (request_body)['callBackUrl']
        md5_command = md5_key (_command)
        if not pidlist.has_key (md5_command):
            start_response ('200 OK', [('Content-Type', 'application/json')])
            return [json.dumps ({'result': 'there is no such rtsp', 'code': 400})]
        else:
            self.end (md5_command, _pid, _callBackUrl)
            start_response ('200 OK', [('Content-Type', 'application/json')])
            return [json.dumps ({'code': 200})]

    @callback
    def end(self, command, pid, callBackUrl=None):
        self.log.logger.info (u'删除pid:{}'.format (pid))
        Popen (['kill -9 {}'.format (pid)], shell=True)
        #lock.acquire ()
        try:
            pidlist.pop (command)
        except:
            pass
        #lock.release ()
        self.log.logger.info (u'本次停止的回调地址为:{}'.format (callBackUrl))
        res = requests.post (callBackUrl, json={'pid': pid, 'result': 'success', 'remarks': 'stop video'})
        self.log.logger.info (res.status_code)

    def restart(self, environ, start_response):
        start_response ('202 OK', [('Content-Type', 'application/json')])
        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)
        _command = eval (request_body)['command']
        _callBackUrl = eval (request_body)['callBackUrl']
        self.log.logger.info (u'重启回调地址是:{}'.format (_callBackUrl))
        self.reflush (_command, _callBackUrl)
        return [json.dumps ({'code': 202})]

    @callback
    def reflush(self, command, callBackUrl=None):
        if md5_key (command) in pidlist.keys ():
            self.log.logger.info (u'进行视频重启')
            _pid = pidlist[md5_key (command)]
            Popen (['kill -9 {}'.format (_pid)], shell=True)
            #lock.acquire ()
            try:
                pidlist.pop (md5_key (command))
            except:
                pass
            #lock.release()
            self.begin (command, callBackUrl)
        else:
            self.begin (command, callBackUrl)

    def application(self, environ, start_response):
        urlpatterns = self.routers ()
        path = environ["PATH_INFO"]
        func = None
        for url, function in urlpatterns:
            if url == path:
                func = function
                break
        if func:
            return func (environ, start_response)
        else:
            HTML_ROOT_DIR = "50x.html"
            start_response ('404 not found', [('Content-Type', 'text/html')])
            with open (HTML_ROOT_DIR) as f:
                return f.read ()


if __name__ == '__main__':
    config = ConfigObj ("lgq.ini", encoding='UTF8')
    host = config['command']['host']
    port = config['command']['port']
    kill_child (str (port))
    for pid in old_pidset:
        print (u'存在僵尸进程:{},已经kill掉!'.format (pid))
        os.popen ("kill -9 %s" % pid)
    time.sleep (3)
    httpd = make_server (host, int (port), rtsp ().application)
    print 'Serving HTTP on port %s...' % port
    httpd.serve_forever ()

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值