AWS Lambda "errorMessage":“[Errno 26] 文本文件忙”
AWS Lambda "errorMessage": "[Errno 26] Text file busy"
我编写代码并通过 AWS SAM CLI 成功将其上传到 AWS Lambda。它基本上进入了我给的 URL ,并打印了网站的标题。一个非常初级的代码。下面是我的代码:
import os, shutil, uuid, time
from selenium import webdriver
def setup():
BIN_DIR = "/tmp/bin"
if not os.path.exists(BIN_DIR):
print("Creating bin folder")
os.makedirs(BIN_DIR)
LIB_DIR = '/tmp/bin/lib'
if not os.path.exists(LIB_DIR):
print("Creating lib folder")
os.makedirs(LIB_DIR)
for filename in ['chromedriver', 'headless-chromium', 'lib/libgconf-2.so.4', 'lib/libORBit-2.so.0']:
oldfile = f'/opt/{filename}'
newfile = f'{BIN_DIR}/{filename}'
shutil.copy2(oldfile, newfile)
os.chmod(newfile, 0o775)
def init_web_driver():
setup()
chrome_options = webdriver.ChromeOptions()
_tmp_folder = '/tmp/{}'.format(uuid.uuid4())
if not os.path.exists(_tmp_folder):
os.makedirs(_tmp_folder)
if not os.path.exists(_tmp_folder + '/user-data'):
os.makedirs(_tmp_folder + '/user-data')
if not os.path.exists(_tmp_folder + '/data-path'):
os.makedirs(_tmp_folder + '/data-path')
if not os.path.exists(_tmp_folder + '/cache-dir'):
os.makedirs(_tmp_folder + '/cache-dir')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1280x1696')
chrome_options.add_argument('--user-data-dir={}'.format(_tmp_folder + '/user-data'))
chrome_options.add_argument('--hide-scrollbars')
chrome_options.add_argument('--enable-logging')
chrome_options.add_argument('--log-level=0')
chrome_options.add_argument('--v=99')
chrome_options.add_argument('--single-process')
chrome_options.add_argument('--data-path={}'.format(_tmp_folder + '/data-path'))
chrome_options.add_argument('--ignore-certificate-errors')
chrome_options.add_argument('--homedir={}'.format(_tmp_folder))
chrome_options.add_argument('--disk-cache-dir={}'.format(_tmp_folder + '/cache-dir'))
chrome_options.add_argument(
'user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36')
chrome_options.binary_location = "/tmp/bin/headless-chromium"
driver = webdriver.Chrome(chrome_options=chrome_options)
return driver
def lambda_handler(event, context):
driver = init_web_driver()
driver.get("http://www.mjlivesey.co.uk")
time.sleep(4)
print(driver.title)
当我第一次点击“测试”按钮时,我可以在输出屏幕中看到“driver.title”。但是,当我在几秒钟后再次单击时,出现以下错误:
{
"errorMessage": "[Errno 26] Text file busy: '/tmp/bin/chromedriver'",
"errorType": "OSError",
"stackTrace": [
" File \"/var/task/app.py\", line 61, in lambda_handler\n driver = init_web_driver()\n",
" File \"/var/task/app.py\", line 22, in init_web_driver\n setup()\n",
" File \"/var/task/app.py\", line 18, in setup\n shutil.copy2(oldfile, newfile)\n",
" File \"/var/lang/lib/python3.7/shutil.py\", line 266, in copy2\n copyfile(src, dst, follow_symlinks=follow_symlinks)\n",
" File \"/var/lang/lib/python3.7/shutil.py\", line 121, in copyfile\n with open(dst, 'wb') as fdst:\n"
]
}
如果我等待半小时或更长时间,我可以再次 运行 代码成功。我不明白这里的问题。或许你们能帮我看清重点。
谢谢。
似乎同一个函数的多次调用都触及了相同的文件,而之前的执行在这些文件上仍然有一个活动锁。
要了解此行为,了解 Lambda Execution environment 的实际工作方式很有用。基本上,如果你在短时间内多次执行相同的功能,AWS 会尝试重用相同的执行环境和资源;这样可以节省时间和资源。
只是为了并行,所发生的事情与在本地并行多次执行您的代码是一样的。由于所有进程都在同一个 files/folders 上读取和写入,因此将不可避免地出现竞争条件。
在您的情况下,您应该重构 setup
函数,使其内容在每个执行环境中只执行一次。
此外,您应该注意 /tmp
目录的硬限制为 512MB,超过 512MB 后您的函数将被终止。如果你想保留你的数据 and/or 有更多的余量,你应该考虑研究 attaching EFS to your lambda.
为了补充之前的答案,我使用了相同的代码,我发现这可以删除 tmp 文件夹并启用后续的 lambdas 运行。
def setup():
BIN_DIR = "/tmp/bin"
if not os.path.exists(BIN_DIR):
print("Creating bin folder")
os.makedirs(BIN_DIR)
else:
print("Delete all files in folder")
for filename in os.listdir(BIN_DIR):
file_path = os.path.join(BIN_DIR, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print('Failed to delete %s. Reason: %s' % (file_path, e))
print("Deleting bin folder")
os.rmdir(BIN_DIR)
print("Creating bin folder")
os.makedirs(BIN_DIR)
只需添加
driver.quit()
在您的代码末尾
我编写代码并通过 AWS SAM CLI 成功将其上传到 AWS Lambda。它基本上进入了我给的 URL ,并打印了网站的标题。一个非常初级的代码。下面是我的代码:
import os, shutil, uuid, time
from selenium import webdriver
def setup():
BIN_DIR = "/tmp/bin"
if not os.path.exists(BIN_DIR):
print("Creating bin folder")
os.makedirs(BIN_DIR)
LIB_DIR = '/tmp/bin/lib'
if not os.path.exists(LIB_DIR):
print("Creating lib folder")
os.makedirs(LIB_DIR)
for filename in ['chromedriver', 'headless-chromium', 'lib/libgconf-2.so.4', 'lib/libORBit-2.so.0']:
oldfile = f'/opt/{filename}'
newfile = f'{BIN_DIR}/{filename}'
shutil.copy2(oldfile, newfile)
os.chmod(newfile, 0o775)
def init_web_driver():
setup()
chrome_options = webdriver.ChromeOptions()
_tmp_folder = '/tmp/{}'.format(uuid.uuid4())
if not os.path.exists(_tmp_folder):
os.makedirs(_tmp_folder)
if not os.path.exists(_tmp_folder + '/user-data'):
os.makedirs(_tmp_folder + '/user-data')
if not os.path.exists(_tmp_folder + '/data-path'):
os.makedirs(_tmp_folder + '/data-path')
if not os.path.exists(_tmp_folder + '/cache-dir'):
os.makedirs(_tmp_folder + '/cache-dir')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1280x1696')
chrome_options.add_argument('--user-data-dir={}'.format(_tmp_folder + '/user-data'))
chrome_options.add_argument('--hide-scrollbars')
chrome_options.add_argument('--enable-logging')
chrome_options.add_argument('--log-level=0')
chrome_options.add_argument('--v=99')
chrome_options.add_argument('--single-process')
chrome_options.add_argument('--data-path={}'.format(_tmp_folder + '/data-path'))
chrome_options.add_argument('--ignore-certificate-errors')
chrome_options.add_argument('--homedir={}'.format(_tmp_folder))
chrome_options.add_argument('--disk-cache-dir={}'.format(_tmp_folder + '/cache-dir'))
chrome_options.add_argument(
'user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36')
chrome_options.binary_location = "/tmp/bin/headless-chromium"
driver = webdriver.Chrome(chrome_options=chrome_options)
return driver
def lambda_handler(event, context):
driver = init_web_driver()
driver.get("http://www.mjlivesey.co.uk")
time.sleep(4)
print(driver.title)
当我第一次点击“测试”按钮时,我可以在输出屏幕中看到“driver.title”。但是,当我在几秒钟后再次单击时,出现以下错误:
{
"errorMessage": "[Errno 26] Text file busy: '/tmp/bin/chromedriver'",
"errorType": "OSError",
"stackTrace": [
" File \"/var/task/app.py\", line 61, in lambda_handler\n driver = init_web_driver()\n",
" File \"/var/task/app.py\", line 22, in init_web_driver\n setup()\n",
" File \"/var/task/app.py\", line 18, in setup\n shutil.copy2(oldfile, newfile)\n",
" File \"/var/lang/lib/python3.7/shutil.py\", line 266, in copy2\n copyfile(src, dst, follow_symlinks=follow_symlinks)\n",
" File \"/var/lang/lib/python3.7/shutil.py\", line 121, in copyfile\n with open(dst, 'wb') as fdst:\n"
]
}
如果我等待半小时或更长时间,我可以再次 运行 代码成功。我不明白这里的问题。或许你们能帮我看清重点。
谢谢。
似乎同一个函数的多次调用都触及了相同的文件,而之前的执行在这些文件上仍然有一个活动锁。
要了解此行为,了解 Lambda Execution environment 的实际工作方式很有用。基本上,如果你在短时间内多次执行相同的功能,AWS 会尝试重用相同的执行环境和资源;这样可以节省时间和资源。
只是为了并行,所发生的事情与在本地并行多次执行您的代码是一样的。由于所有进程都在同一个 files/folders 上读取和写入,因此将不可避免地出现竞争条件。
在您的情况下,您应该重构 setup
函数,使其内容在每个执行环境中只执行一次。
此外,您应该注意 /tmp
目录的硬限制为 512MB,超过 512MB 后您的函数将被终止。如果你想保留你的数据 and/or 有更多的余量,你应该考虑研究 attaching EFS to your lambda.
为了补充之前的答案,我使用了相同的代码,我发现这可以删除 tmp 文件夹并启用后续的 lambdas 运行。
def setup():
BIN_DIR = "/tmp/bin"
if not os.path.exists(BIN_DIR):
print("Creating bin folder")
os.makedirs(BIN_DIR)
else:
print("Delete all files in folder")
for filename in os.listdir(BIN_DIR):
file_path = os.path.join(BIN_DIR, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print('Failed to delete %s. Reason: %s' % (file_path, e))
print("Deleting bin folder")
os.rmdir(BIN_DIR)
print("Creating bin folder")
os.makedirs(BIN_DIR)
只需添加
driver.quit()
在您的代码末尾