From 86666474b2d61712dd092486bf2cc25d773e9d90 Mon Sep 17 00:00:00 2001 From: bwnfo3 Date: Tue, 23 Sep 2025 11:49:25 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20execution=5Forder=20=EC=BB=AC?= =?UTF-8?q?=EB=9F=BC=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/site/icebang/domain/execution/model/TaskRun.java | 4 +++- .../main/java/site/icebang/domain/workflow/dto/TaskDto.java | 1 + .../src/main/resources/mybatis/mapper/JobMapper.xml | 3 ++- .../src/main/resources/mybatis/mapper/TaskRunMapper.xml | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/user-service/src/main/java/site/icebang/domain/execution/model/TaskRun.java b/apps/user-service/src/main/java/site/icebang/domain/execution/model/TaskRun.java index f1ae2239..9eb9028d 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/execution/model/TaskRun.java +++ b/apps/user-service/src/main/java/site/icebang/domain/execution/model/TaskRun.java @@ -12,6 +12,7 @@ public class TaskRun { private Long id; private Long jobRunId; private Long taskId; + private Integer executionOrder; private String status; // PENDING, RUNNING, SUCCESS, FAILED private String resultMessage; // 실행 결과 메시지 private LocalDateTime startedAt; @@ -27,8 +28,9 @@ private TaskRun(Long jobRunId, Long taskId) { } /** Task 실행 시작을 위한 정적 팩토리 메서드 */ - public static TaskRun start(Long jobRunId, Long taskId) { + public static TaskRun start(Long jobRunId, Long taskId, Integer executionOrder) { TaskRun taskRun = new TaskRun(jobRunId, taskId); + taskRun.executionOrder = executionOrder; taskRun.status = "RUNNING"; taskRun.startedAt = LocalDateTime.now(); return taskRun; diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/dto/TaskDto.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/dto/TaskDto.java index 54a0ca08..286e7e8c 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/dto/TaskDto.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/dto/TaskDto.java @@ -11,6 +11,7 @@ public class TaskDto { private Long id; private String name; private String type; + private Integer executionOrder; private JsonNode parameters; private LocalDateTime createdAt; private LocalDateTime updatedAt; diff --git a/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml index 4d5b1e60..f27012ff 100644 --- a/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml +++ b/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml @@ -23,6 +23,7 @@ + @@ -36,7 +37,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/user-service/src/main/resources/sql/03-insert-workflow.sql b/apps/user-service/src/main/resources/sql/03-insert-workflow.sql index fc9f39c2..0660b31f 100644 --- a/apps/user-service/src/main/resources/sql/03-insert-workflow.sql +++ b/apps/user-service/src/main/resources/sql/03-insert-workflow.sql @@ -14,10 +14,13 @@ DELETE FROM `workflow`; -- =================================================================== -- 워크플로우 생성 (ID: 1) -INSERT INTO `workflow` (`id`, `name`, `description`, `created_by`) VALUES - (1, '상품 분석 및 블로그 자동 발행', '키워드 검색부터 상품 분석 후 블로그 발행까지의 자동화 프로세스', 1) - ON DUPLICATE KEY UPDATE name = VALUES(name), description = VALUES(description), updated_at = NOW(); - +INSERT INTO `workflow` (`id`, `name`, `description`, `created_by`, `default_config`) VALUES + (1, '상품 분석 및 블로그 자동 발행', '키워드 검색부터 상품 분석 후 블로그 발행까지의 자동화 프로세스', 1, + JSON_OBJECT('keyword_search',json_object('tag','naver'),'blog_publish',json_object('tag','naver_blog','blog_id', 'wtecho331', 'blog_pw', 'testpass'))) +ON DUPLICATE KEY UPDATE + name = VALUES(name), + description = VALUES(description), + updated_at = NOW(); -- Job 생성 (ID: 1, 2) INSERT INTO `job` (`id`, `name`, `description`, `created_by`) VALUES (1, '상품 분석', '키워드 검색, 상품 크롤링 및 유사도 분석 작업', 1), From 00384d1cfb767f50cc97303a97cba468fdad695f Mon Sep 17 00:00:00 2001 From: thkim7 Date: Tue, 23 Sep 2025 15:04:03 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20mecab=EB=9D=BC=EC=9D=B4=EB=B8=8C?= =?UTF-8?q?=EB=9F=AC=EB=A6=AC=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20dockerfil?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pre-processing-service/Dockerfile | 47 +++++++++++++++++-- .../app/utils/keyword_matcher.py | 16 +++---- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/apps/pre-processing-service/Dockerfile b/apps/pre-processing-service/Dockerfile index 383ea749..2a9d9736 100644 --- a/apps/pre-processing-service/Dockerfile +++ b/apps/pre-processing-service/Dockerfile @@ -2,14 +2,20 @@ FROM python:3.11-slim AS builder WORKDIR /app -# 필수 OS 패키지 -RUN apt-get update && apt-get install -y --no-install-recommends curl \ +# 필수 OS 패키지 (기존 + Chrome 설치용 패키지 추가) +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + wget \ + unzip \ + gnupg \ + ca-certificates \ && rm -rf /var/lib/apt/lists/* # Poetry 설치 RUN curl -sSL https://install.python-poetry.org | python3 - ENV PATH="/root/.local/bin:$PATH" RUN poetry self add "poetry-plugin-export>=1.7.0" + # 런타임 가상환경 RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" @@ -23,6 +29,38 @@ RUN poetry export --without dev -f requirements.txt -o requirements.txt \ FROM python:3.11-slim AS final WORKDIR /app +# Chrome과 ChromeDriver 설치를 위한 패키지 설치 +RUN apt-get update && apt-get install -y --no-install-recommends \ + wget \ + unzip \ + curl \ + gnupg \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Chrome 설치 +RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends google-chrome-stable && \ + rm -rf /var/lib/apt/lists/* + +# ChromeDriver 설치 +RUN LATEST_VERSION=$(curl -s "https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_STABLE") && \ + wget -O /tmp/chromedriver-linux64.zip "https://storage.googleapis.com/chrome-for-testing-public/${LATEST_VERSION}/linux64/chromedriver-linux64.zip" && \ + unzip /tmp/chromedriver-linux64.zip -d /tmp/ && \ + mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin/chromedriver && \ + chmod +x /usr/local/bin/chromedriver && \ + rm -rf /tmp/* && \ + apt-get clean + +# MeCab & 사전 설치 (형태소 분석 의존) +RUN apt-get update && apt-get install -y --no-install-recommends \ + mecab \ + libmecab-dev \ + mecab-ipadic-utf8 \ + && rm -rf /var/lib/apt/lists/* + # /opt/venv 복사 COPY --from=builder /opt/venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" @@ -31,5 +69,8 @@ ENV PATH="/opt/venv/bin:$PATH" COPY . . +# 환경변수로 MeCab 경로 지정 +ENV MECAB_PATH=/usr/lib/mecab/dic/ipadic + # (권장 대안) 코드에서 uvicorn import 안 하고 프로세스 매니저로 실행하려면: -ENTRYPOINT ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "app.main:app", "-b", "0.0.0.0:8000"] +ENTRYPOINT ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "app.main:app", "-b", "0.0.0.0:8000"] \ No newline at end of file diff --git a/apps/pre-processing-service/app/utils/keyword_matcher.py b/apps/pre-processing-service/app/utils/keyword_matcher.py index e9ae48ac..6806b140 100644 --- a/apps/pre-processing-service/app/utils/keyword_matcher.py +++ b/apps/pre-processing-service/app/utils/keyword_matcher.py @@ -1,3 +1,5 @@ +import os + from app.core.config import settings # pydantic_settings 기반 from loguru import logger @@ -15,26 +17,22 @@ class KeywordMatcher: - """키워드 매칭 분석기""" - def __init__(self): self.konlpy_available = False - - # MeCab 사용 가능 여부 확인 if MECAB_AVAILABLE: try: - # 경로가 있으면 사용, 없으면 기본값 - if settings.mecab_path: - self.mecab = MeCab.Tagger(f"-d {settings.mecab_path}") + # 환경변수 MECAB_PATH가 있으면 사용, 없으면 기본값 + mecab_path = os.getenv("MECAB_PATH") + if mecab_path: + self.mecab = MeCab.Tagger(f"-d {mecab_path}") else: self.mecab = MeCab.Tagger() # 기본 경로 - # 테스트 실행 test_result = self.mecab.parse("테스트") if test_result and test_result.strip(): self.konlpy_available = True logger.info( - f"MeCab 형태소 분석기 사용 가능 (경로: {settings.mecab_path or '기본'})" + f"MeCab 형태소 분석기 사용 가능 (경로: {mecab_path or '기본'})" ) else: logger.warning("MeCab 테스트 실패")