Enhance temp file handling with error tracking and update Docker Compose to run as non-root user
Some checks failed
CI / test (3.10) (push) Has been cancelled

This commit is contained in:
remsky 2025-03-29 17:01:15 -06:00
parent d0c13f6401
commit 65f6b979c3
4 changed files with 57 additions and 76 deletions

View file

@ -1,55 +0,0 @@
# name: Sync develop with master
# on:
# push:
# branches:
# - master
# jobs:
# sync-develop:
# runs-on: ubuntu-latest
# permissions:
# contents: write
# issues: write
# steps:
# - name: Checkout repository
# uses: actions/checkout@v4
# with:
# fetch-depth: 0
# ref: develop
# - name: Configure Git
# run: |
# git config user.name "GitHub Actions"
# git config user.email "actions@github.com"
# - name: Merge master into develop
# run: |
# git fetch origin master:master
# git merge --no-ff origin/master -m "chore: Merge master into develop branch"
# - name: Push changes
# run: |
# if ! git push origin develop; then
# echo "Failed to push to develop branch"
# exit 1
# fi
# - name: Handle Failure
# if: failure()
# uses: actions/github-script@v7
# with:
# script: |
# const issueBody = `Automatic merge from master to develop failed.
# Please resolve this manually
# Workflow run: ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
# await github.rest.issues.create({
# owner: context.repo.owner,
# repo: context.repo.repo,
# title: '🔄 Automatic master to develop merge failed',
# body: issueBody,
# labels: ['merge-failed', 'automation']
# });

View file

@ -215,6 +215,10 @@ async def create_speech(
"Transfer-Encoding": "chunked",
"X-Download-Path": download_path,
}
# Add header to indicate if temp file writing is available
if temp_writer._write_error:
headers["X-Download-Status"] = "unavailable"
# Create async generator for streaming
async def dual_output():

View file

@ -81,26 +81,36 @@ class TempFileWriter:
self.format = format
self.temp_file = None
self._finalized = False
self._write_error = False # Flag to track if we've had a write error
async def __aenter__(self):
"""Async context manager entry"""
# Clean up old files first
await cleanup_temp_files()
try:
# Clean up old files first
await cleanup_temp_files()
# Create temp file with proper extension
await aiofiles.os.makedirs(settings.temp_file_dir, exist_ok=True)
temp = tempfile.NamedTemporaryFile(
dir=settings.temp_file_dir,
delete=False,
suffix=f".{self.format}",
mode="wb",
)
self.temp_file = await aiofiles.open(temp.name, mode="wb")
self.temp_path = temp.name
temp.close() # Close sync file, we'll use async version
# Create temp file with proper extension
await aiofiles.os.makedirs(settings.temp_file_dir, exist_ok=True)
temp = tempfile.NamedTemporaryFile(
dir=settings.temp_file_dir,
delete=False,
suffix=f".{self.format}",
mode="wb",
)
self.temp_file = await aiofiles.open(temp.name, mode="wb")
self.temp_path = temp.name
temp.close() # Close sync file, we'll use async version
# Generate download path immediately
self.download_path = f"/download/{os.path.basename(self.temp_path)}"
# Generate download path immediately
self.download_path = f"/download/{os.path.basename(self.temp_path)}"
except Exception as e:
# Handle permission issues or other errors gracefully
logger.error(f"Failed to create temp file: {e}")
self._write_error = True
# Set a placeholder path so the API can still function
self.temp_path = f"unavailable_{self.format}"
self.download_path = f"/download/{self.temp_path}"
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
@ -111,6 +121,7 @@ class TempFileWriter:
self._finalized = True
except Exception as e:
logger.error(f"Error closing temp file: {e}")
self._write_error = True
async def write(self, chunk: bytes) -> None:
"""Write a chunk of audio data
@ -120,9 +131,18 @@ class TempFileWriter:
"""
if self._finalized:
raise RuntimeError("Cannot write to finalized temp file")
await self.temp_file.write(chunk)
await self.temp_file.flush()
# Skip writing if we've already encountered an error
if self._write_error or not self.temp_file:
return
try:
await self.temp_file.write(chunk)
await self.temp_file.flush()
except Exception as e:
# Handle permission issues or other errors gracefully
logger.error(f"Failed to write to temp file: {e}")
self._write_error = True
async def finalize(self) -> str:
"""Close temp file and return download path
@ -133,7 +153,18 @@ class TempFileWriter:
if self._finalized:
raise RuntimeError("Temp file already finalized")
await self.temp_file.close()
self._finalized = True
# Skip finalizing if we've already encountered an error
if self._write_error or not self.temp_file:
self._finalized = True
return self.download_path
try:
await self.temp_file.close()
self._finalized = True
except Exception as e:
# Handle permission issues or other errors gracefully
logger.error(f"Failed to finalize temp file: {e}")
self._write_error = True
self._finalized = True
return f"/download/{os.path.basename(self.temp_path)}"
return self.download_path

View file

@ -7,6 +7,7 @@ services:
dockerfile: docker/gpu/Dockerfile
volumes:
- ../../api:/app/api
user: "1001:1001" # Ensure container runs as UID 1001 (appuser)
ports:
- "8880:8880"
environment: