我有一个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