feat: release 2.2.0 with PC-only tests and execution reliability fixes
Unify task scheduling and queue state, fix Android input and observation recovery, preserve screenshot paths, and match final review criteria accurately. Add collapsible copyable results and publish the complete 2.1.0 upgrade notes. Validation: 3189 backend tests, 326 frontend tests, 24 client tests, production build and quality gates.
This commit is contained in:
1 parent
fac4ccb760
commit
be6e8c2abd
79 files changed
+2263
-277
No files matched your search
@@ -51,7 +51,9 @@ class TaskOptions(BaseModel):
|
||||
action_failure_attempts: int | None = Field(default=None, ge=1, le=10)
|
||||
worker_cleanup_timeout_seconds: float | None = Field(default=None, gt=0, le=300)
|
||||
plugins: list[PluginSelection] | None = None
|
||||
execution_target: ExecutionTarget | None = None
|
||||
execution_target: ExecutionTarget | None = Field(
|
||||
default=None, description="android (default), computer (PC only, no Android), or mixed"
|
||||
)
|
||||
|
||||
@field_serializer("recording", when_used="unless-none")
|
||||
def serialize_recording(self, value: RecordingConfig) -> dict:
|
||||
@@ -117,6 +119,17 @@ def template() -> bytes:
|
||||
),
|
||||
]
|
||||
)
|
||||
help_sheet.append(
|
||||
[
|
||||
"示例-PC-001",
|
||||
"电脑桌面",
|
||||
"浏览器检查",
|
||||
"仅 PC 测试",
|
||||
"已启用并授权提供画面观察的电脑插件,无需手机或模拟器在线",
|
||||
"打开电脑浏览器,访问指定网页并核对实际结果。",
|
||||
json.dumps({"profile": "flash", "execution_target": "computer"}, ensure_ascii=False),
|
||||
]
|
||||
)
|
||||
for column in range(1, 8):
|
||||
help_sheet.column_dimensions[get_column_letter(column)].width = 70 if column > 5 else 26
|
||||
for row in help_sheet:
|
||||
|
||||
@@ -346,7 +346,7 @@ class TaskQueueService:
|
||||
|
||||
@classmethod
|
||||
def _concurrency_limit(cls) -> int:
|
||||
"""Return 0 for per-device concurrency, or the global task limit."""
|
||||
"""Return the shared global single-task limit, including computer targets."""
|
||||
return DeviceExecutionLock.resolve_env_concurrency()
|
||||
|
||||
@classmethod
|
||||
@@ -354,10 +354,8 @@ class TaskQueueService:
|
||||
"""Persistent dispatcher scheduling pending tasks onto devices.
|
||||
|
||||
Scans the queue and launches each eligible task as an independent
|
||||
coroutine. Admission is governed by _concurrency_limit(): 0 admits one
|
||||
task per device so distinct devices execute concurrently, N>=1 admits
|
||||
at most N tasks across all devices. Per-device FIFO ordering and
|
||||
cross-process mutual exclusion remain enforced by DeviceExecutionLock
|
||||
coroutine. Admission allows one executing task across all targets.
|
||||
Global FIFO ordering and cross-process mutual exclusion are enforced by DeviceExecutionLock
|
||||
inside each worker process.
|
||||
"""
|
||||
print(
|
||||
@@ -436,6 +434,8 @@ class TaskQueueService:
|
||||
target = cls._task_target(item)
|
||||
resources = set(item.get("plugin_resources", []))
|
||||
if resources & busy_resources:
|
||||
if limit == 1:
|
||||
return
|
||||
continue
|
||||
if limit == 0:
|
||||
# A task without a resolved device may bind to any serial, so it
|
||||
@@ -451,6 +451,8 @@ class TaskQueueService:
|
||||
continue
|
||||
elif limit >= 1 and device is not None and target.lock_key in busy_devices:
|
||||
# A second worker for this device would wait on its lock.
|
||||
if limit == 1:
|
||||
return
|
||||
continue
|
||||
|
||||
item["status"] = "running"
|
||||
|
||||
Reference in new issue
Block a user