热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何将非阻塞stderr捕获添加到线程popen-howtoaddnonblockingstderrcapturetothreadedpopen's

Ivegotapython3scriptiusetobackupandencryptmysqldumpfilesandimhavingaparticularis

I've got a python 3 script i use to backup and encrypt mysqldump files and im having a particular issues with one database that is 67gb after encryption & compression. The mysqldump is outputting errorcode 3, so i'd like to catch the actual error message, as this could mean a couple of things. The random thing is the backup file is the right size, so not sure what the error means. it worked once on this database...

我有一个python 3脚本,我用来备份和加密mysqldump文件,我有一个特殊的问题,一个数据库,加密和压缩后67GB。 mysqldump正在输出错误代码3,所以我想捕获实际的错误消息,因为这可能意味着一些事情。随机的是备份文件的大小合适,所以不确定错误的含义。它在这个数据库上工作过一次......

the code looks like the below and i'd really appreciate some help on how to add non-blocking capture of stderr when the return code is anything but 0 for both p1 and p2.

代码如下所示,我非常感谢有关如何在返回代码为p1和p2的0以外的任何内容时添加非阻塞捕获stderr的一些帮助。

Also, if im doing anything glaringly obvious wrong, please do let me know, as i'd like to make sure this is a reliable process. it has been working fine on my databases under 15gb compressed.

此外,如果我做任何明显错误的事情,请告诉我,因为我想确保这是一个可靠的过程。在15gb压缩下,它在我的数据库上工作正常。

def dbbackup():
    while True:
        item = q.get()
        #build up folder structure, daily, weekly, monthy & project
        genfile = config[item]['DBName'] + '-' + dateyymmdd + '-'
        genfile += config[item]['PubKey'] + '.sql.gpg'
        if os.path.isfile(genfile):
            syslog.syslog(item + ' ' + genfile + ' exists, removing')
            os.remove(genfile)
        syslog.syslog(item + ' will be backed up as ' + genfile)
        args = ['mysqldump', '-u', config[item]['UserNm'],
                '-p' + config[item]['Passwd'], '-P', config[item]['Portnu'],
                '-h', config[item]['Server']]
        args.extend(config[item]['MyParm'].split())
        args.append(config[item]['DBName'])
        p1 = subprocess.Popen(args, stdout=subprocess.PIPE)
        p2 = subprocess.Popen(['gpg', '-o', genfile, '-r',
                               config[item]['PubKey'], '-z', '9', '--encrypt'], stdin=p1.stdout)
        p2.wait()
        if p2.returncode == 0:
            syslog.syslog(item + ' encryption successful')
        else:
            syslog.syslog(syslog.LOG_CRIT, item + ' encryption failed '+str(p2.returncode))
            p1.terminate()
        p1.wait()
        if p1.returncode == 0:
        #does some uploads of the file etc..
        else:
            syslog.syslog(syslog.LOG_CRIT, item + ' extract failed '+str(p1.returncode))
        q.task_done()


def main():
    db2backup = []
    for settingtest in config:
            db2backup.append(settingtest)
    if len(db2backup) >= 1:
        syslog.syslog('Backups started')
        for database in db2backup:
            q.put(database)
            syslog.syslog(database + ' added to backup queue')
        q.join()
        syslog.syslog('Backups finished')


q = queue.Queue()
cOnfig= configparser.ConfigParser()
config.read('backup.cfg')
backuptype = 'daily'
dateyymmdd = datetime.datetime.now().strftime('%Y%m%d')


for i in range(2):
    t = threading.Thread(target=dbbackup)
    t.daemon = True
    t.start()

if __name__ == '__main__':
    main()

1 个解决方案

#1


Simplify your code:

简化您的代码:

  • avoid unnecessary globals, pass parameters to the corresponding functions instead
  • 避免不必要的全局变量,将参数传递给相应的函数

  • avoid reimplementing a thread pool (it hurts readability and it misses convience features accumulated over the years).
  • 避免重新实现一个线程池(它会损害可读性,并且会错过多年积累的便利功能)。

The simplest way to capture stderr is to use stderr=PIPE and .communicate() (blocking call):

捕获stderr的最简单方法是使用stderr = PIPE和.communicate()(阻塞调用):

#!/usr/bin/env python3
from configparser import ConfigParser
from datetime import datetime
from multiprocessing.dummy import Pool
from subprocess import Popen, PIPE

def backup_db(item, conf): # config[item] == conf
    """Run `mysqldump ... | gpg ...` command."""
    genfile = '{conf[DBName]}-{now:%Y%m%d}-{conf[PubKey]}.sql.gpg'.format(
                cOnf=conf, now=datetime.now())
    # ...
    args = ['mysqldump', '-u', conf['UserNm'], ...]
    with Popen(['gpg', ...], stdin=PIPE) as gpg, \
         Popen(args, stdout=gpg.stdin, stderr=PIPE) as db_dump:
        gpg.communicate() 
        error = db_dump.communicate()[1]
    if gpg.returncode or db_dump.returncode:
        error

def main():
    cOnfig= ConfigParser()
    with open('backup.cfg') as file: # raise exception if config is unavailable
        config.read_file(file)
    with Pool(2) as pool:
        pool.starmap(backup_db, config.items())

if __name__ == "__main__":
    main()

NOTE: no need to call db_dump.terminate() if gpg dies prematurely: mysqldump dies when it tries to write something to the closed gpg.stdin.

注意:如果gpg过早死亡,则无需调用db_dump.terminate():mysqldump在尝试向关闭的gpg.stdin写入内容时死亡。

If there are huge number of items in the config then you could use pool.imap() instead of pool.starmap() (the call should be modified slightly).

如果配置中有大量项目,那么您可以使用pool.imap()而不是pool.starmap()(应稍微修改调用)。

For robustness, wrap backup_db() function to catch and log all exceptions.

为了提高健壮性,请将backup_db()函数包装起来以捕获并记录所有异常。


推荐阅读
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • MySQL语句大全:创建、授权、查询、修改等【MySQL】的使用方法详解
    本文详细介绍了MySQL语句的使用方法,包括创建用户、授权、查询、修改等操作。通过连接MySQL数据库,可以使用命令创建用户,并指定该用户在哪个主机上可以登录。同时,还可以设置用户的登录密码。通过本文,您可以全面了解MySQL语句的使用方法。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 本文介绍了使用Python解析C语言结构体的方法,包括定义基本类型和结构体类型的字典,并提供了一个示例代码,展示了如何解析C语言结构体。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 先看一段错误日志:###Errorqueryingdatabase.Cause:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransie ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
author-avatar
全哥-广州仔1
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有