[build/fs/copy] use fs.copyFile to avoid race condition (#32220) (#32239)

Fixes #31913

There have been 6 failures in this test in the last 60 days, which I believe is caused by a race condition of some sort that prevents us from accessing the file right after it's been written. It might have to do with writeStreams not actually flushing to the filesystem within time, but I haven't been able to prove it. @mikecote is taking a look at seeing if he can do some simple testing to reproduce the situation locally.

In order to avoid further errors this PR updates to use the `fs.copyFile` function that was added in node 8.5, which does the whole copy in a single native operation.
This commit is contained in:
Spencer 2019-02-28 14:09:38 -08:00 committed by GitHub
parent 3131293760
commit ad8a40cac5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 5 additions and 13 deletions

View file

@ -34,11 +34,11 @@ import { Extract } from 'tar';
const mkdirpAsync = promisify(mkdirpCb);
const statAsync = promisify(fs.stat);
const chmodAsync = promisify(fs.chmod);
const writeFileAsync = promisify(fs.writeFile);
const readFileAsync = promisify(fs.readFile);
const readdirAsync = promisify(fs.readdir);
const utimesAsync = promisify(fs.utimes);
const copyFileAsync = promisify(fs.copyFile);
export function assertAbsolute(path) {
if (!isAbsolute(path)) {
@ -80,19 +80,10 @@ export async function copy(source, destination) {
assertAbsolute(source);
assertAbsolute(destination);
const stat = await statAsync(source);
// mkdirp after the stat(), stat will throw if source
// doesn't exist and ideally we won't create the parent directory
// unless the source exists
// do a stat call to make sure the source exists before creating the destination directory
await statAsync(source);
await mkdirp(dirname(destination));
await createPromiseFromStreams([
fs.createReadStream(source),
fs.createWriteStream(destination),
]);
await chmodAsync(destination, stat.mode);
await copyFileAsync(source, destination, fs.constants.COPYFILE_FICLONE);
}
export async function deleteAll(patterns, log) {

View file

@ -78,6 +78,7 @@ export default function ({ getService, getPageObjects }) {
describe('cancel button', () => {
it('discards the pipeline and redirects to the list', async () => {
await PageObjects.logstash.gotoPipelineList();
await pipelineList.assertExists();
const originalRows = await pipelineList.readRows();
await PageObjects.logstash.gotoNewPipelineEditor();