Skip to content

Commit 7387c71

Browse files
committed
fix(backend): process_todo、batch_process_todo接口优化 #8303
1 parent 0e7eff3 commit 7387c71

File tree

4 files changed

+56
-19
lines changed

4 files changed

+56
-19
lines changed

dbm-ui/backend/ticket/handler.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
99
specific language governing permissions and limitations under the License.
1010
"""
11+
import asyncio
1112
import itertools
1213
import json
1314
import logging
@@ -43,6 +44,7 @@
4344
from backend.ticket.serializers import TodoSerializer
4445
from backend.ticket.todos import BaseTodoContext, TodoActorFactory
4546
from backend.ticket.todos.itsm_todo import ItsmTodoContext
47+
from backend.utils.batch_request import async_func
4648

4749
logger = logging.getLogger("root")
4850

@@ -287,13 +289,23 @@ def batch_process_todo(cls, user, action, operations):
287289
@param action 动作
288290
@param operations: todo列表,每个item包含todo id和params
289291
"""
290-
291-
results = []
292+
# 批量处理待办操作
293+
operation_contents = []
292294
for operation in operations:
293-
todo_id, params = operation["todo_id"], operation["params"]
294-
todo = Todo.objects.get(id=todo_id)
295-
TodoActorFactory.actor(todo).process(user, action, params)
296-
results.append(todo)
295+
operation_contents.append(
296+
(
297+
operation["todo_id"],
298+
operation["params"],
299+
action,
300+
user,
301+
)
302+
)
303+
304+
# 执行异步处理
305+
asyncio.run(async_func(TicketHandler.process_single_todo, operation_contents))
306+
307+
# 获取处理后的待办事项
308+
results = [Todo.objects.get(id=operation["todo_id"]) for operation in operations]
297309
return TodoSerializer(results, many=True).data
298310

299311
@classmethod
@@ -458,3 +470,11 @@ def ticket_status_standardization(cls):
458470
context=ItsmTodoContext(itsm_flow.id, ticket.id).to_dict(),
459471
)
460472
print(f"ticket[{ticket.id}] add a itsm todo")
473+
474+
@classmethod
475+
def process_single_todo(cls, todo_id, params, act, username):
476+
"""
477+
处理单个待办的辅助函数
478+
"""
479+
todo = Todo.objects.select_related("ticket").prefetch_related("ticket__flows").get(id=todo_id)
480+
TodoActorFactory.actor(todo).process(username, act, params)

dbm-ui/backend/ticket/models/ticket.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,22 +146,21 @@ def current_flow(self) -> Flow:
146146
1. 取 TicketFlow 中最后一个 flow_obj_id 非空的流程
147147
2. 若 TicketFlow 中都流程都为空,则代表整个单据未开始,取第一个流程
148148
"""
149-
if Flow.objects.filter(ticket=self).exclude(status=TicketFlowStatus.PENDING).exists():
150-
return Flow.objects.filter(ticket=self).exclude(status=TicketFlowStatus.PENDING).last()
149+
non_pending_flows = [flow for flow in self.flows.all() if flow.status != TicketFlowStatus.PENDING]
150+
if non_pending_flows:
151+
# 返回最后一个符合条件的 Flow 对象
152+
return non_pending_flows[-1]
151153
# 初始化时,当前节点和下一个节点为同一个
152154
return self.next_flow()
153155

154156
def next_flow(self) -> Flow:
155157
"""
156158
下一个流程,即 TicketFlow 中第一个为PENDING的流程
157159
"""
158-
next_flows = Flow.objects.filter(ticket=self, status=TicketFlowStatus.PENDING)
160+
next_flows = [flow for flow in self.flows.all() if flow.status == TicketFlowStatus.PENDING]
159161

160-
# 支持跳过人工审批和确认环节
161-
if env.ITSM_FLOW_SKIP:
162-
next_flows = next_flows.exclude(flow_type__in=[FlowType.BK_ITSM, FlowType.PAUSE])
163-
164-
return next_flows.first()
162+
# 返回第一个符合条件的 Flow 对象
163+
return next_flows[0] if next_flows else None
165164

166165
@classmethod
167166
def create_ticket(

dbm-ui/backend/ticket/views.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@
8282
TodoSerializer,
8383
UpdateTicketFlowConfigSerializer,
8484
)
85-
from backend.ticket.todos import TodoActorFactory
8685

8786
TICKET_TAG = "ticket"
8887

@@ -240,6 +239,7 @@ def perform_create(self, serializer):
240239
builder.patch_ticket_detail()
241240
builder.init_ticket_flows()
242241

242+
ticket = Ticket.objects.prefetch_related("flows").get(pk=ticket.pk)
243243
TicketFlowManager(ticket=ticket).run_next_flow()
244244

245245
@swagger_auto_schema(
@@ -426,10 +426,9 @@ def process_todo(self, request, *args, **kwargs):
426426
ticket = self.get_object()
427427

428428
validated_data = self.params_validate(self.get_serializer_class())
429-
430-
todo = ticket.todo_of_ticket.get(id=validated_data["todo_id"])
431-
TodoActorFactory.actor(todo).process(request.user.username, validated_data["action"], validated_data["params"])
432-
429+
TicketHandler.process_single_todo(
430+
validated_data["todo_id"], validated_data["params"], validated_data["action"], request.user.username
431+
)
433432
return Response(TodoSerializer(ticket.todo_of_ticket.all(), many=True).data)
434433

435434
@common_swagger_auto_schema(

dbm-ui/backend/utils/batch_request.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
99
specific language governing permissions and limitations under the License.
1010
"""
11+
import asyncio
12+
import concurrent.futures
1113
from concurrent.futures import ThreadPoolExecutor, as_completed
1214
from copy import deepcopy
1315
from multiprocessing.pool import ThreadPool
@@ -226,3 +228,20 @@ def wrapper(wrapped, instance, args, kwargs):
226228
return {"data": data, "total": len(data)}
227229

228230
return wrapper
231+
232+
233+
async def async_func(func, params_list):
234+
"""
235+
通用异步函数
236+
@param func: 需要并发执行的函数
237+
@param params_list: 参数列表,每个元素是一个元组,包含传递给 func 的参数
238+
"""
239+
240+
loop = asyncio.get_running_loop()
241+
242+
# 自定义线程池
243+
with concurrent.futures.ThreadPoolExecutor() as executor:
244+
# 将所有的任务提交到线程池
245+
tasks = [loop.run_in_executor(executor, func, *params) for params in params_list]
246+
# 等待所有任务完成
247+
await asyncio.gather(*tasks)

0 commit comments

Comments
 (0)