Persist failed AI generation records

This commit is contained in:
王鹏
2026-05-22 12:19:28 +08:00
parent a3608381ed
commit 4936d31d3b
3 changed files with 78 additions and 7 deletions

View File

@@ -19,7 +19,6 @@ import com.ruoyi.generator.domain.front.dto.DatabaseDesignResponse;
import com.ruoyi.generator.domain.front.dto.DatabaseTableDesign;
import com.ruoyi.generator.domain.front.dto.GenerateDatabaseRequest;
import com.ruoyi.generator.mapper.front.FrontProjectColumnMapper;
import com.ruoyi.generator.mapper.front.FrontProjectGenerationMapper;
import com.ruoyi.generator.mapper.front.FrontProjectMapper;
import com.ruoyi.generator.mapper.front.FrontProjectTableMapper;
@@ -41,7 +40,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
@Autowired
private FrontProjectColumnMapper frontProjectColumnMapper;
@Autowired
private FrontProjectGenerationMapper frontProjectGenerationMapper;
private AiGenerationRecordService generationRecordService;
@Override
@Transactional
@@ -63,7 +62,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
generation.setResponsePayload(aiContent);
generation.setSuccess("1");
generation.setElapsedMs(System.currentTimeMillis() - start);
frontProjectGenerationMapper.insertFrontProjectGeneration(generation);
generationRecordService.insert(generation);
return response;
}
catch (RuntimeException e)
@@ -71,7 +70,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
generation.setSuccess("0");
generation.setErrorMessage(e.getMessage());
generation.setElapsedMs(System.currentTimeMillis() - start);
frontProjectGenerationMapper.insertFrontProjectGeneration(generation);
generationRecordService.insert(generation);
throw e;
}
}

View File

@@ -0,0 +1,21 @@
package com.ruoyi.generator.service.front;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.generator.domain.front.FrontProjectGeneration;
import com.ruoyi.generator.mapper.front.FrontProjectGenerationMapper;
@Service
public class AiGenerationRecordService
{
@Autowired
private FrontProjectGenerationMapper frontProjectGenerationMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insert(FrontProjectGeneration generation)
{
frontProjectGenerationMapper.insertFrontProjectGeneration(generation);
}
}

View File

@@ -1,17 +1,25 @@
package com.ruoyi.generator.service.front;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.generator.config.DeepSeekProperties;
import com.ruoyi.generator.domain.front.FrontProject;
import com.ruoyi.generator.domain.front.FrontProjectColumn;
@@ -38,17 +46,20 @@ public class AiGenerateServiceImplTest
private FrontProjectColumnMapper frontProjectColumnMapper;
@Mock
private FrontProjectGenerationMapper frontProjectGenerationMapper;
private AiGenerationRecordService generationRecordService;
@Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
service = new AiGenerateServiceImpl();
generationRecordService = new AiGenerationRecordService();
setField(generationRecordService, "frontProjectGenerationMapper", frontProjectGenerationMapper);
setField("deepSeekClient", deepSeekClient);
setField("frontProjectMapper", frontProjectMapper);
setField("frontProjectTableMapper", frontProjectTableMapper);
setField("frontProjectColumnMapper", frontProjectColumnMapper);
setField("frontProjectGenerationMapper", frontProjectGenerationMapper);
setField("generationRecordService", generationRecordService);
setField("validator", new AiDatabaseSchemaValidator());
setField("ddlBuilder", new MysqlDdlBuilder());
setField("deepSeekProperties", new DeepSeekProperties());
@@ -76,11 +87,51 @@ public class AiGenerateServiceImplTest
assertTrue(response.getSql().contains("CREATE TABLE `car_info`"));
}
@Test
public void generateDatabasePersistsFailureGenerationRecordBeforePropagatingClientFailure()
{
RuntimeException failure = new RuntimeException("DeepSeek unavailable");
when(frontProjectMapper.selectFrontProjectByUserAndId(7L, 10L)).thenReturn(project());
when(deepSeekClient.chat(anyString())).thenThrow(failure);
try
{
service.generateDatabase(7L, 10L, request());
fail("Expected client failure");
}
catch (RuntimeException e)
{
assertSame(failure, e);
}
ArgumentCaptor<FrontProjectGeneration> generationCaptor = ArgumentCaptor.forClass(FrontProjectGeneration.class);
verify(frontProjectGenerationMapper).insertFrontProjectGeneration(generationCaptor.capture());
assertEquals("0", generationCaptor.getValue().getSuccess());
assertEquals("DeepSeek unavailable", generationCaptor.getValue().getErrorMessage());
verify(frontProjectColumnMapper, never()).deleteColumnsByProjectId(10L);
verify(frontProjectTableMapper, never()).deleteTablesByProjectId(10L);
}
@Test
public void generationRecordInsertUsesRequiresNewTransaction() throws Exception
{
Method method = AiGenerationRecordService.class.getDeclaredMethod("insert", FrontProjectGeneration.class);
Transactional transactional = method.getAnnotation(Transactional.class);
assertNotNull(transactional);
assertEquals(Propagation.REQUIRES_NEW, transactional.propagation());
}
private void setField(String name, Object value) throws Exception
{
Field field = AiGenerateServiceImpl.class.getDeclaredField(name);
setField(service, name, value);
}
private void setField(Object target, String name, Object value) throws Exception
{
Field field = target.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(service, value);
field.set(target, value);
}
private FrontProject project()