扩展外部生成Worker队列
新增外部生成队列概览和单任务状态契约 将跳一跳、拼消消、敲木鱼图片生成动作接入worker队列 前端生成等待页展示当前任务和队列数量 更新外部生成worker运维文档和团队决策记录
This commit is contained in:
@@ -104,6 +104,12 @@ pub struct ExternalGenerationJobFailInput {
|
||||
pub failed_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct ExternalGenerationJobGetInput {
|
||||
pub job_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct ExternalGenerationJobSnapshot {
|
||||
pub job_id: String,
|
||||
@@ -218,6 +224,17 @@ pub fn fail_external_generation_job_and_return(
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn get_external_generation_job_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
input: ExternalGenerationJobGetInput,
|
||||
) -> ExternalGenerationJobProcedureResult {
|
||||
match ctx.try_with_tx(|tx| get_external_generation_job_tx(tx, input.clone())) {
|
||||
Ok(job) => single_external_generation_job_result(job),
|
||||
Err(message) => failed_external_generation_job_result(message),
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn get_external_generation_queue_stats_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
@@ -405,6 +422,28 @@ fn complete_external_generation_job_tx(
|
||||
Ok(map_external_generation_job_row(row))
|
||||
}
|
||||
|
||||
fn get_external_generation_job_tx(
|
||||
ctx: &ReducerContext,
|
||||
input: ExternalGenerationJobGetInput,
|
||||
) -> Result<ExternalGenerationJobSnapshot, String> {
|
||||
validate_required("external_generation_job.job_id", &input.job_id)?;
|
||||
validate_required(
|
||||
"external_generation_job.owner_user_id",
|
||||
&input.owner_user_id,
|
||||
)?;
|
||||
let row = ctx
|
||||
.db
|
||||
.external_generation_job()
|
||||
.job_id()
|
||||
.find(&input.job_id.trim().to_string())
|
||||
.ok_or_else(|| "external_generation_job 不存在".to_string())?;
|
||||
if row.owner_user_id.trim() != input.owner_user_id.trim() {
|
||||
return Err("external_generation_job 不存在".to_string());
|
||||
}
|
||||
|
||||
Ok(map_external_generation_job_row(row))
|
||||
}
|
||||
|
||||
fn renew_external_generation_job_lease_tx(
|
||||
ctx: &ReducerContext,
|
||||
input: ExternalGenerationJobRenewLeaseInput,
|
||||
|
||||
@@ -345,6 +345,9 @@ fn compile_puzzle_clear_draft_tx(
|
||||
if input.generation_status.as_deref() == Some(PUZZLE_CLEAR_GENERATION_FAILED) {
|
||||
return mark_puzzle_clear_generation_failed_tx(ctx, input, session);
|
||||
}
|
||||
if input.generation_status.as_deref() == Some(PUZZLE_CLEAR_GENERATION_GENERATING) {
|
||||
return mark_puzzle_clear_generation_generating_tx(ctx, input, session);
|
||||
}
|
||||
let pattern_groups: Vec<PuzzleClearPatternGroupSnapshot> = input
|
||||
.pattern_groups_json
|
||||
.as_deref()
|
||||
@@ -457,6 +460,71 @@ fn compile_puzzle_clear_draft_tx(
|
||||
)
|
||||
}
|
||||
|
||||
fn mark_puzzle_clear_generation_generating_tx(
|
||||
ctx: &ReducerContext,
|
||||
input: PuzzleClearDraftCompileInput,
|
||||
session: PuzzleClearAgentSessionRow,
|
||||
) -> Result<PuzzleClearAgentSessionSnapshot, String> {
|
||||
let updated_at = Timestamp::from_micros_since_unix_epoch(input.compiled_at_micros);
|
||||
let mut draft = if session.draft_json.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
parse_json::<PuzzleClearDraftSnapshot>(&session.draft_json).ok()
|
||||
}
|
||||
.unwrap_or_else(|| PuzzleClearDraftSnapshot {
|
||||
template_id: PUZZLE_CLEAR_TEMPLATE_ID.to_string(),
|
||||
template_name: PUZZLE_CLEAR_TEMPLATE_NAME.to_string(),
|
||||
profile_id: Some(input.profile_id.clone()),
|
||||
work_title: clean_string(&input.work_title, PUZZLE_CLEAR_TEMPLATE_NAME),
|
||||
work_description: input.work_description.trim().to_string(),
|
||||
theme_prompt: clean_string(&input.theme_prompt, PUZZLE_CLEAR_TEMPLATE_NAME),
|
||||
generate_board_background: input.generate_board_background,
|
||||
board_background_asset: None,
|
||||
board_background_prompt: clean_string(&input.board_background_prompt, &input.theme_prompt),
|
||||
card_back_image_src: Some(PUZZLE_CLEAR_CARD_BACK_IMAGE_SRC.to_string()),
|
||||
atlas_asset: None,
|
||||
pattern_groups: Vec::new(),
|
||||
card_assets: Vec::new(),
|
||||
generation_status: PUZZLE_CLEAR_GENERATION_GENERATING.to_string(),
|
||||
});
|
||||
draft.profile_id = Some(input.profile_id.clone());
|
||||
draft.work_title = clean_string(&input.work_title, PUZZLE_CLEAR_TEMPLATE_NAME);
|
||||
draft.work_description = input.work_description.trim().to_string();
|
||||
draft.theme_prompt = clean_string(&input.theme_prompt, PUZZLE_CLEAR_TEMPLATE_NAME);
|
||||
draft.generate_board_background = input.generate_board_background;
|
||||
draft.board_background_prompt =
|
||||
clean_string(&input.board_background_prompt, &input.theme_prompt);
|
||||
if let Some(board_background_asset) = input
|
||||
.board_background_asset_json
|
||||
.as_deref()
|
||||
.map(parse_json)
|
||||
.transpose()?
|
||||
{
|
||||
draft.board_background_asset = Some(board_background_asset);
|
||||
}
|
||||
draft.generation_status = PUZZLE_CLEAR_GENERATION_GENERATING.to_string();
|
||||
|
||||
replace_session(
|
||||
ctx,
|
||||
&session,
|
||||
PuzzleClearAgentSessionRow {
|
||||
status: PUZZLE_CLEAR_GENERATION_GENERATING.to_string(),
|
||||
draft_json: to_json_string(&draft),
|
||||
published_profile_id: input.profile_id,
|
||||
updated_at,
|
||||
..clone_session(&session)
|
||||
},
|
||||
);
|
||||
|
||||
get_puzzle_clear_agent_session_tx(
|
||||
ctx,
|
||||
PuzzleClearAgentSessionGetInput {
|
||||
session_id: input.session_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn mark_puzzle_clear_generation_failed_tx(
|
||||
ctx: &ReducerContext,
|
||||
input: PuzzleClearDraftCompileInput,
|
||||
|
||||
Reference in New Issue
Block a user