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.DatabaseTableDesign;
import com.ruoyi.generator.domain.front.dto.GenerateDatabaseRequest; import com.ruoyi.generator.domain.front.dto.GenerateDatabaseRequest;
import com.ruoyi.generator.mapper.front.FrontProjectColumnMapper; 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.FrontProjectMapper;
import com.ruoyi.generator.mapper.front.FrontProjectTableMapper; import com.ruoyi.generator.mapper.front.FrontProjectTableMapper;
@@ -41,7 +40,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
@Autowired @Autowired
private FrontProjectColumnMapper frontProjectColumnMapper; private FrontProjectColumnMapper frontProjectColumnMapper;
@Autowired @Autowired
private FrontProjectGenerationMapper frontProjectGenerationMapper; private AiGenerationRecordService generationRecordService;
@Override @Override
@Transactional @Transactional
@@ -63,7 +62,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
generation.setResponsePayload(aiContent); generation.setResponsePayload(aiContent);
generation.setSuccess("1"); generation.setSuccess("1");
generation.setElapsedMs(System.currentTimeMillis() - start); generation.setElapsedMs(System.currentTimeMillis() - start);
frontProjectGenerationMapper.insertFrontProjectGeneration(generation); generationRecordService.insert(generation);
return response; return response;
} }
catch (RuntimeException e) catch (RuntimeException e)
@@ -71,7 +70,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
generation.setSuccess("0"); generation.setSuccess("0");
generation.setErrorMessage(e.getMessage()); generation.setErrorMessage(e.getMessage());
generation.setElapsedMs(System.currentTimeMillis() - start); generation.setElapsedMs(System.currentTimeMillis() - start);
frontProjectGenerationMapper.insertFrontProjectGeneration(generation); generationRecordService.insert(generation);
throw e; 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; package com.ruoyi.generator.service.front;
import static org.junit.Assert.assertEquals; 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.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.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; 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.config.DeepSeekProperties;
import com.ruoyi.generator.domain.front.FrontProject; import com.ruoyi.generator.domain.front.FrontProject;
import com.ruoyi.generator.domain.front.FrontProjectColumn; import com.ruoyi.generator.domain.front.FrontProjectColumn;
@@ -38,17 +46,20 @@ public class AiGenerateServiceImplTest
private FrontProjectColumnMapper frontProjectColumnMapper; private FrontProjectColumnMapper frontProjectColumnMapper;
@Mock @Mock
private FrontProjectGenerationMapper frontProjectGenerationMapper; private FrontProjectGenerationMapper frontProjectGenerationMapper;
private AiGenerationRecordService generationRecordService;
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
service = new AiGenerateServiceImpl(); service = new AiGenerateServiceImpl();
generationRecordService = new AiGenerationRecordService();
setField(generationRecordService, "frontProjectGenerationMapper", frontProjectGenerationMapper);
setField("deepSeekClient", deepSeekClient); setField("deepSeekClient", deepSeekClient);
setField("frontProjectMapper", frontProjectMapper); setField("frontProjectMapper", frontProjectMapper);
setField("frontProjectTableMapper", frontProjectTableMapper); setField("frontProjectTableMapper", frontProjectTableMapper);
setField("frontProjectColumnMapper", frontProjectColumnMapper); setField("frontProjectColumnMapper", frontProjectColumnMapper);
setField("frontProjectGenerationMapper", frontProjectGenerationMapper); setField("generationRecordService", generationRecordService);
setField("validator", new AiDatabaseSchemaValidator()); setField("validator", new AiDatabaseSchemaValidator());
setField("ddlBuilder", new MysqlDdlBuilder()); setField("ddlBuilder", new MysqlDdlBuilder());
setField("deepSeekProperties", new DeepSeekProperties()); setField("deepSeekProperties", new DeepSeekProperties());
@@ -76,11 +87,51 @@ public class AiGenerateServiceImplTest
assertTrue(response.getSql().contains("CREATE TABLE `car_info`")); 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 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.setAccessible(true);
field.set(service, value); field.set(target, value);
} }
private FrontProject project() private FrontProject project()