bcp在一批100多个工作中随机失败

时间:2016-11-29 20:54:35

标签: python sql-server multithreading bcp

我有一个Python程序,可生成300多个文件,并使用bcp将它们移动到MSSQL。由于大约生成了21个文件并且同时进行了bcp,因此存在高级别的并发性。这是该计划的关键部分:

    cmd = ['bcp', self.bcptbl, 'IN', outfile, '-f', 'bcpfmt.fmt', '-m1', '-U', uid, '-S', self.srv, '-P', pwd]
    subprocess.check_output(cmd)

一次三个批处理线程,每个7个子线程,所以21个并发进程。随机文件bcp失败并显示错误:

[Microsoft][SQL Server Native Client 11.0]Unable to open BCP host data-file

该错误可能与我在调用BCP之前创建文件的方式有关:

with open(outfile, 'a') as outf:
    proc = Popen('ext_prog.exe', stdin=PIPE, stdout=outf, stderr=PIPE)
    _, err = proc.communicate(input='\n'.join(patterns).encode('latin1'))

有些东西告诉我外部程序没有释放文件句柄,即使文件打开和关闭似乎是我处理的。

这不是典型的错误,因为权限,文件夹,路径等都已正确设置,因为它在失败之前成功复制了80~150个文件。

上述代码中的BCP调用经常失败,直到我在bcp调用之前插入以下检查:

@staticmethod
def wait_file_is_ready(outfile):
    try:
        with open(outfile, 'r'):
            print("File {} is ready for reading".format(outfile))
    except BaseException as e:
        print("File {} is not ready: {}".format(outfile, e))

我的理由是Windows不会将文件标记为关闭,因此打开和关闭它会有所帮助。这修复了99%的错误,但是我今天得到的大量工作又回来困扰着我。

我试图从错误中恢复的东西:

  • 在重新运行相同的bcp命令之前添加1小时的睡眠 - 失败
  • 制作输入文件的副本并重新运行bcp命令 - 失败
  • 从命令行手动运行BCP命令始终有效

更详细的代码摘录:

MAX_THREADS = 7

def start_batch(self):
    ts = []
    self.patternq = queue.Queue()
    self.bcptbl = '"tempdb.dbo.outtbl_{}"'.format(randint(0,1E15))
    for thread_no in range(MAX_THREADS):
        tname = "thread_{:02}_of_{}".format(thread_no, MAX_THREADS)
        t = Thread(name=tname, target=self.load, args=(thread_no,))
        t.start()
        ts.append(t)

    for t in ts:
        t.join()

def load(self, thread_no):
    outfile = "d:\\tmp\\outfile_{}_{:02}.temp".format(
        randint(0,1E15), thread_no)
    try:
        os.unlink(outfile)
    except FileNotFoundError:
        pass
    while True:
        try:
            patterns = self.patternq.get_nowait()
        except queue.Empty:
            break
        with open(outfile, 'a') as outf:
            proc = Popen('ext_prog.exe', stdin=PIPE, stdout=outf, stderr=PIPE)
            _, err = proc.communicate(input='\n'.join(patterns).encode('latin1'))

    cmd = ['bcp', self.bcptbl, 'IN', outfile, '-f', 'bcpfmt.fmt', '-m1', '-U', uid, '-S', self.srv, '-P', pwd]
    try:
        subprocess.check_output(cmd)            
    except subprocess.CalledProcessError as e:
        # OK, it failed because "Unable to open BCP host data-file"
        # How can I recover from it?
        raise

1 个答案:

答案 0 :(得分:0)

我通过使用ODBC来缓慢而谨慎地插入记录来解决这个问题。这在3次中有2次奏效。这是我在第三次迭代时得到的错误:

os.unlink(OUTFILE) PermissionError:[WinError 32]进程无法访问该文件,因为它正由另一个进程使用:'d:\ tmp \ outfile_678410328373703.temp_03'

错误的可行解释: Seems to be an issue long standing and a bug inherent with Windows 7

  

MS forums

中找到了这个      

似乎是一个长期存在的问题,也是Windows 7固有的错误。

     

MS没有承认此错误的“官方”声明因此不太可能发布修补程序或修补程序。上面的线程中的一些用户提供了“修复”但是它们在工作流生产率方面太耗时且效率低。这不应该是购买新操作系统时必须处理的问题......