新增PDF生成并发设置
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import threading
|
||||
from datetime import date, datetime, timedelta
|
||||
from pathlib import Path
|
||||
from time import monotonic
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
@@ -10,6 +12,35 @@ from app.models import Certificate, CertificateAccessToken, Learner, ProjectCour
|
||||
DESIGN_WIDTH = 1024
|
||||
DESIGN_HEIGHT = 759
|
||||
PDF_BASE_RESOLUTION = 150.0
|
||||
PDF_GENERATION_WAIT_TIMEOUT_SECONDS = 120
|
||||
|
||||
|
||||
class PdfGenerationBusy(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class PdfGenerationLimiter:
|
||||
def __init__(self) -> None:
|
||||
self._condition = threading.Condition()
|
||||
self._active = 0
|
||||
|
||||
def acquire(self, limit: int, timeout_seconds: int = PDF_GENERATION_WAIT_TIMEOUT_SECONDS) -> None:
|
||||
deadline = monotonic() + timeout_seconds
|
||||
with self._condition:
|
||||
while self._active >= limit:
|
||||
remaining = deadline - monotonic()
|
||||
if remaining <= 0:
|
||||
raise PdfGenerationBusy("当前PDF生成任务较多,请稍后重试")
|
||||
self._condition.wait(remaining)
|
||||
self._active += 1
|
||||
|
||||
def release(self) -> None:
|
||||
with self._condition:
|
||||
self._active = max(0, self._active - 1)
|
||||
self._condition.notify_all()
|
||||
|
||||
|
||||
pdf_generation_limiter = PdfGenerationLimiter()
|
||||
|
||||
|
||||
def pdf_cache_path(certificate_no: str) -> Path:
|
||||
@@ -51,6 +82,7 @@ def render_certificate_pdf(
|
||||
learner: Learner,
|
||||
project: ProjectCourse | None,
|
||||
token: CertificateAccessToken,
|
||||
concurrency_limit: int = 2,
|
||||
) -> Path:
|
||||
output_path = pdf_cache_path(certificate.certificate_no)
|
||||
template_path = certificate_template_path()
|
||||
@@ -60,8 +92,15 @@ def render_certificate_pdf(
|
||||
update_pdf_access_time(certificate)
|
||||
return output_path
|
||||
|
||||
image = render_certificate_image(certificate, learner, project)
|
||||
image.save(output_path, "PDF", resolution=pdf_resolution(image))
|
||||
pdf_generation_limiter.acquire(max(1, concurrency_limit))
|
||||
try:
|
||||
if cached_pdf_is_fresh(output_path) and output_path.stat().st_mtime >= latest_renderer_mtime:
|
||||
update_pdf_access_time(certificate)
|
||||
return output_path
|
||||
image = render_certificate_image(certificate, learner, project)
|
||||
image.save(output_path, "PDF", resolution=pdf_resolution(image))
|
||||
finally:
|
||||
pdf_generation_limiter.release()
|
||||
|
||||
certificate.pdf_status = "generated"
|
||||
certificate.pdf_file_path = str(output_path)
|
||||
|
||||
Reference in New Issue
Block a user