Skip to content

Conversation

@charmander
Copy link
Contributor

and do a best-effort directory fsync after the rename before inserting them into the database.

It’s unlikely, but very bad, for a partially-written media file to be served by nginx (which doesn’t consult the media table) with Cache-Control: immutable.

It would be nice if we could use the standard library’s tempfile.NamedTemporaryFile for this, but its deletion options are too limited to be much cleaner, and it sets different file permissions.

It’s unlikely, but very bad, for a partially-written media file to be served by nginx (which doesn’t consult the `media` table) with `Cache-Control: immutable`.

It would be nice if we could use the standard library’s `tempfile.NamedTemporaryFile` for this, but its deletion options are too limited to be much cleaner, and it sets different file permissions.
…dia` table row

Might as well?

`os.open` applies `O_CLOEXEC` by default.

This comment was marked as resolved.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +53 to +69
with _os_closing(os.open(dir_path, os.O_RDONLY | os.O_DIRECTORY)) as dir_fd:
temp_name = f"tmp-{os.urandom(8).hex()}"
outfile = open(temp_name, "xb", opener=partial(os.open, dir_fd=dir_fd))

try:
with outfile:
outfile.write(data)
outfile.flush()
os.fsync(outfile)
except:
os.unlink(temp_name, dir_fd=dir_fd)
raise

os.replace(temp_name, hash_filename, src_dir_fd=dir_fd, dst_dir_fd=dir_fd)

# Try to make sure the hash-named file is persisted before inserting it into the database
os.fsync(dir_fd)
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new atomic file creation logic (lines 53-69) lacks test coverage. Consider adding tests to verify: 1) temporary files are cleaned up on write failures, 2) the atomic rename succeeds, and 3) the fsync operations complete without errors. The existing tests in libweasyl/test/test_media.py only verify successful file creation paths.

Copilot uses AI. Check for mistakes.
@charmander charmander requested a review from huntertur January 2, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant