2016-11-29 47 views
0

我有一个Python程序,可以生成超过300个文件并使用bcp将它们移动到MSSQL。由于大约21个文件正在生成和同时进行,因此存在较高的并发性。这里是程序的关键部分:bcp在一批超过100个作业中随机失败

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%的错误,但我今天得到的大量工作回来困扰着我。

事情我试图从错误中恢复:

  • 添加了1个小时的睡眠重新运行相同的BCP命令之前 - 失败
  • 进行输入文件的副本重新运行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 

回答

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

Found this in MS forums

Seems to be an issue long standing and a bug inherent with Windows 7.

There has been no "official" statement from MS acknowledging this bug hence a patch or fix release is unlikely. Some users in the thread above have offered "fixes" but they are way too time consuming and inefficient in regards to workflow productivity. This shouldn't be an issue one has to deal with when purchasing a new OS ...