-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
fix: make session copy resilient by skipping locked files (EBUSY) #3546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: make session copy resilient by skipping locked files (EBUSY) #3546
Conversation
Replaced the direct call to fs.copy() with a recursive, file-by-file resilient copy strategy. This change prevents the session compression process from failing entirely when a single file is locked or in use (common with RemoteAuth files like `.wwebjs_auth/RemoteAuth.plain`). - Locked or in-use files (EBUSY) are now skipped with a warning. - All other session files are still copied correctly. - This improves compatibility on both Windows and Linux environments.
This is my first contribution to the project, so I really appreciate your patience if something isn’t 100% aligned with the PR conventions 🙏 I couldn’t find an open issue that directly addressed the error I was facing, but I wanted to share the context in case it helps others. The issue was related to saving the RemoteAuth session, especially when files like This is the error:
To solve this, I implemented a resilient copy function that skips locked files and continues copying the rest. This dramatically improved session handling in my setup. For context, here’s the custom import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as fs from 'fs';
import { WhatsAppSession } from 'src/model/whatsapp-session.entity';
@Injectable()
export class TypeOrmStore {
constructor(
@InjectRepository(WhatsAppSession)
private readonly repo: Repository<WhatsAppSession>,
) {}
async getAllSessions(): Promise<{ sessionId: string }[]> {
return this.repo.find({ select: ['sessionId'] });
}
async sessionExists({ session }: { session: string }): Promise<boolean> {
return this.repo.exists({ where: { sessionId: this.getSessionId(session) } });
}
async save({ session }: { session: string }): Promise<void> {
const zipPath = `${session}.zip`;
const data = await fs.promises.readFile(zipPath);
await this.repo.save({
sessionId: this.getSessionId(session),
data,
});
}
async extract({ session, path }: { session: string; path: string }): Promise<void> {
const row = await this.repo.findOneBy({
sessionId: this.getSessionId(session),
});
if (!row) return;
await fs.promises.writeFile(path, row.data);
}
async delete({ session }: { session: string }): Promise<void> {
await this.repo.delete({
sessionId: this.getSessionId(session),
});
}
private getSessionId(session: string): string {
return session.replaceAll('RemoteAuth-', '');
}
} |
Seems the lint gods are not yet happy, but we currently do not seem to log anything in the file. @alechkos will let you know how to handle this. unfortunately I am not familiar with running this on windows, yet the solution seems to be a good addition as long as we do not skip necessary files. have you found any flaws when trying to restore a session? I would assume we may run into issues at some point for missing vital files. |
@themazim .wwebjs_auth/RemoteAuth-artific/Default/Sessions/Session_13391086524750032 Let me check the lint :) |
@stevefold @themazim @jrocha @tegila who could follow up on this? :) |
When you not copy the locked files you make the session failed or not be up to date |
src/authStrategies/RemoteAuth.js
Outdated
try { | ||
const stat = await fs.stat(srcPath); | ||
if (stat.isDirectory()) { | ||
await this.copyResilient(srcPath, destPath); // recursividad para subcarpetas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No Spanish comments please
const srcPath = path.join(srcDir, item); | ||
const destPath = path.join(destDir, item); | ||
|
||
/*eslint no-empty: "error"*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the exception of eslint, let it give the error
@@ -145,7 +145,7 @@ class RemoteAuth extends BaseAuthStrategy { | |||
const archive = archiver('zip'); | |||
const stream = fs.createWriteStream(`${this.sessionName}.zip`); | |||
|
|||
await fs.copy(this.userDataDir, this.tempDir).catch(() => {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use fs.cp(src,des,{"recursive":true})
?
https://nodejs.org/docs/latest-v20.x/api/fs.html#fspromisescpsrc-dest-options
Replaced the direct call to fs.copy() with a recursive, file-by-file resilient copy strategy.
This change prevents the session compression process from failing entirely when a single file is locked or in use (common with RemoteAuth files like
.wwebjs_auth/RemoteAuth-artific/Default/Sessions/Session_13391086524750032
).PR Details
Replaces the use of
fs.copy()
with a custom recursive copy function that skips over locked files (like.wwebjs_auth/RemoteAuth-artific/Default/Sessions/Session_13391086524750032
auth files) to prevent full session copy failure. This improves reliability when compressing sessions on systems where certain files may be held open.Description
copyResilient()
, a recursive method to copy directories file-by-file.EBUSY
, it is skipped and logged as a warning.fs.copy()
incompressSession()
with this resilient approach.Related Issue(s)
Possibly related to RemoteAuth session issues on Windows and Linux reported by various users.
Motivation and Context
Some users have reported intermittent failures when trying to backup or compress sessions, particularly when using RemoteAuth. This PR ensures that such failures no longer prevent the rest of the session from being saved.
How Has This Been Tested
.wwebjs_auth/RemoteAuth-artific/Default/Sessions/Session_13391086524750032
by keeping client open.Environment
whatsapp-web.js@1.27.0
2.2407.3
whatsapp-web.js
)Types of changes
Checklist