fix(storage): prevent project data loss with backup and auto-save (#2…#6539
Conversation
|
❌ Some Jest tests failed. Please check the logs and fix the issues before merging. Failed Tests: |
|
@walterbender Can you review this PR |
could you also check this test which is failing on the main branch |
|
hy @parthdagia05 sorry can't review on my own i am in collage |
706e569 to
5e0db6b
Compare
|
❌ Some Jest tests failed. Please check the logs and fix the issues before merging. Failed Tests: |
|
made a little changes, could you check it out again ?
|
| pitchDuration = toFraction(pitchDuration); | ||
| const adjustedNote = _adjustPitch(pitch.name, keySignature).toUpperCase(); | ||
| if (triplet != null) { | ||
| if (triplet !== null && triplet !== undefined) { |
There was a problem hiding this comment.
Please revert this change.
| } catch (e) { | ||
| console.error("[AutoSave] Failed:", e); | ||
| } | ||
| }, 60000); |
There was a problem hiding this comment.
Maybe every 5 minutes? One reason we never did this in the past was because we didn't want to interrupt playback. So maybe defer is the project is actively running? (Esp. because we'll have saved right before running.)
There was a problem hiding this comment.
Changed from 60s to 5 minutes (5 * 60 * 1000). Added a guard: if (this.logo && this.logo._alreadyRunning) return; so auto-save is skipped during playback.
| // prevent unnecessary crashing | ||
|
|
||
| if (savedjsonobj == null) throw new Error("Failed to save project data"); | ||
| if (savedjsonobj === null || savedjsonobj === undefined) |
There was a problem hiding this comment.
does == null cover both cases?
There was a problem hiding this comment.
does == null covers both the cases reverting the changes
|
In general, this looks very good. |
5e0db6b to
0586623
Compare
|
✅ All Jest tests passed! This PR is ready to merge. |
…to-save (sugarlabs#2994) Addresses the root causes of student project data loss: - Add backup-on-save: persists a copy under a separate key before each write - Add corruption recovery: restore() falls back to backup when primary is corrupt - Add error handling in save() with concurrency guard to prevent race conditions - Prevent initialiseStorage() from overwriting backup when data is null - Add 60-second auto-save in activity.js that captures live workspace blocks via prepareExport() + saveLocally(), not just a storage-layer flush - Clean up auto-save interval on beforeunload - Fix pre-existing eslint eqeqeq warnings in touched files - Add module.exports for testability - Add 43 comprehensive tests covering all storage protection mechanisms Closes sugarlabs#2994
0586623 to
80f5a70
Compare
|
✅ All Jest tests passed! This PR is ready to merge. |
|
@walterbender made the changes could you recheck |
Summary
Fixes #2994
Students have reported losing all their locally saved projects after a browser crash or page refresh. The root cause is that all project data is stored under a single key (
ProjectData) in IndexedDB via localforage. If that entry gets corrupted during a crash,restore()silently returns null, andinitialiseStorage()overwrites everything with an empty object permanently destroying all projects with no way to recover.This PR addresses the problem with four targeted changes to
ProjectStorage.js:Changes
Backup before write
Every call to
save()now persists a copy of the current stored data under a separateProjectData_backupkey before overwriting the primary. This ensures a known-good snapshot always exists.Corruption recovery in
restore()If the primary data fails to parse (corrupted JSON), the system now automatically attempts to restore from the backup key. Only if both primary and backup are unavailable does it initialize a fresh empty state.
Error handling and concurrency guard in
save()save()is wrapped in try/catch so a storage failure (quota exceeded, disk error) no longer propagates as an unhandled exception that could crash the app.A
_saveInProgressflag prevents overlapping writes that could cause race conditions.Periodic auto-save (60s interval)
A
setIntervaltimer callssave()every 60 seconds, so if the browser crashes between user-triggered saves, at most one minute of work is lost instead of everything.Safe initialization
initialiseStorage()now skips callingsave()when data was null/corrupted, preventing it from overwriting the backup with empty data during recovery.How it was tested
Added 43 unit tests covering:
Ran the full test suite (4232 tests pass, no regressions introduced)
Verified with integration tests that simulate the exact Student Loses Project Twice #2994 scenario:
Category
-[X] Bug Fix
-[X] Tests