Skip to content

Commit cb6e366

Browse files
author
zhansheng.lzs
committed
fix(reinforcement): preserve FaaS business errors and request context
1 parent 845987e commit cb6e366

4 files changed

Lines changed: 349 additions & 15 deletions

File tree

‎dashscope/applications/finetune/reinforcement/common/model.py‎

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@
107107
_LAYER_STATUS_QUERY_SOLUTION = (
108108
"Retry the layer status query after connectivity recovers."
109109
)
110+
_LAYER_STATUS_REJECTED_SOLUTION = (
111+
"Review the server response and layer code. For region lookup errors, "
112+
"report the request ID and layer code to the service owner before retrying."
113+
)
110114
_LAYER_BUILD_FAILED_SOLUTION = (
111115
"Check that requirements.txt or setup.py is valid and every dependency "
112116
"is installable, then review the layer build logs before retrying."
@@ -121,6 +125,15 @@
121125
)
122126

123127

128+
def _fc_response_rejected(result: Dict[str, Any]) -> bool:
129+
status = result.get("status")
130+
return (
131+
(isinstance(status, dict) and status.get("code", 200) != 200)
132+
or result.get("code") not in (None, "", 0, 200)
133+
or result.get("success") is False
134+
)
135+
136+
124137
class MountStorage(BaseModel):
125138
model_config = ConfigDict(extra="forbid")
126139

@@ -447,14 +460,27 @@ async def create_layer(
447460
# "signed_url": oss_signed_url,
448461
},
449462
)
450-
if result.get("status", {}).get("code", 500) != 200:
463+
if _fc_response_rejected(result):
451464
raise FunctionLayerError(
452-
f"create rejected by server | {result}",
465+
f"create rejected by server | {deep_mask(result)}",
466+
layer_name=layer_name,
467+
request_id=result.get("request_id"),
468+
body=result,
453469
allow_retry=False,
454470
solution=_LAYER_CREATE_REJECTED_SOLUTION,
455471
)
456472

457-
layer_code = result.get("output", {}).get("layer_code", "")
473+
layer_code = (result.get("output") or {}).get("layer_code", "")
474+
if not layer_code:
475+
raise FunctionLayerError(
476+
f"Empty layer code received: {deep_mask(result)}",
477+
error_code=2013,
478+
layer_name=layer_name,
479+
request_id=result.get("request_id"),
480+
body=result,
481+
allow_retry=False,
482+
solution=_LAYER_CREATE_REJECTED_SOLUTION,
483+
)
458484
logger.debug(
459485
f"Create function layer | layer-name: {layer_name} | "
460486
f"layer_code: {layer_code}",
@@ -564,7 +590,19 @@ async def get_layer(
564590
solution=_LAYER_STATUS_QUERY_SOLUTION,
565591
) from e
566592

567-
status = result.get("output", {}).get("status", "")
593+
if _fc_response_rejected(result):
594+
raise FunctionLayerError(
595+
f"status query rejected by server | layer_code: "
596+
f"{layer_code} | {deep_mask(result)}",
597+
error_code=2016,
598+
layer_code=layer_code,
599+
request_id=result.get("request_id"),
600+
body=result,
601+
allow_retry=False,
602+
solution=_LAYER_STATUS_REJECTED_SOLUTION,
603+
)
604+
605+
status = (result.get("output") or {}).get("status", "")
568606

569607
if status == "SUCCESS":
570608
logger.debug(
@@ -579,6 +617,8 @@ async def get_layer(
579617
f"{layer_code} | {result}",
580618
error_code=2015,
581619
layer_code=layer_code,
620+
request_id=result.get("request_id"),
621+
body=result,
582622
allow_retry=False,
583623
solution=_LAYER_BUILD_FAILED_SOLUTION,
584624
)
@@ -589,6 +629,8 @@ async def get_layer(
589629
f"{layer_code} | {result}",
590630
error_code=2016,
591631
layer_code=layer_code,
632+
request_id=result.get("request_id"),
633+
body=result,
592634
allow_retry=True,
593635
solution=_LAYER_STATUS_MISSING_SOLUTION,
594636
)
@@ -808,6 +850,8 @@ async def register(
808850
message=f"Function layer deployment failed: {root}",
809851
),
810852
output={},
853+
request_id=e.request_id,
854+
body=e.body,
811855
)
812856
except Exception as e:
813857
root = e
@@ -934,22 +978,36 @@ async def load(
934978
url,
935979
runtime_dict,
936980
)
937-
self.instance_id = result.get("output", {}).get("instanceId", "")
981+
if _fc_response_rejected(result):
982+
raise FunctionLoadError(
983+
f"load rejected by server | {deep_mask(result)}",
984+
error_code=2023,
985+
entity_id=target_entity_id,
986+
request_id=result.get("request_id"),
987+
body=result,
988+
allow_retry=False,
989+
)
990+
991+
output = result.get("output") or {}
992+
self.instance_id = output.get("instanceId", "")
938993
if not self.instance_id:
939994
raise FunctionLoadError(
940-
f"Empty instance ID received: {result}",
995+
f"Empty instance ID received: {deep_mask(result)}",
941996
error_code=2023,
997+
entity_id=target_entity_id,
998+
request_id=result.get("request_id"),
999+
body=result,
9421000
)
9431001

944-
self.instance_url = result.get("output", {}).get("trigger_url", "")
945-
self.instance_token = result.get("output", {}).get(
946-
"trigger_token",
947-
"",
948-
)
1002+
self.instance_url = output.get("trigger_url", "")
1003+
self.instance_token = output.get("trigger_token", "")
9491004
if (not self.instance_url) or (not self.instance_token):
9501005
raise FunctionLoadError(
9511006
"Missing instance URL or token",
9521007
error_code=2024,
1008+
entity_id=target_entity_id,
1009+
request_id=result.get("request_id"),
1010+
body=result,
9531011
)
9541012

9551013
logger.info(
@@ -978,6 +1036,8 @@ async def load(
9781036
),
9791037
),
9801038
output={},
1039+
request_id=e.request_id,
1040+
body=e.body,
9811041
)
9821042

9831043
except Exception as e:
@@ -998,6 +1058,8 @@ async def load(
9981058
),
9991059
),
10001060
output={},
1061+
request_id=getattr(e, "request_id", None),
1062+
body=getattr(e, "body", None),
10011063
)
10021064

10031065
# Perform instance warmup if requested
@@ -1627,6 +1689,8 @@ async def register_functions(
16271689
raise RegistrationError(
16281690
reg_result.status.message,
16291691
error_code=2052,
1692+
request_id=reg_result.request_id,
1693+
body=reg_result.body,
16301694
)
16311695

16321696
if fc.type == FunctionType.ROLLOUT:
@@ -1661,8 +1725,11 @@ async def register_functions(
16611725
instance_group_reward_ids.append(instance_id)
16621726
else:
16631727
raise FunctionLoadError(
1664-
f"Load failed: {load_result}",
1728+
f"Load failed: {load_result.status.message}",
16651729
error_code=2054,
1730+
entity_id=entity_id,
1731+
request_id=load_result.request_id,
1732+
body=load_result.body,
16661733
)
16671734

16681735
except Exception as e:

‎dashscope/applications/finetune/reinforcement/common/model_types.py‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding: utf-8 -*-
22
from enum import Enum
33
from typing import Optional, List, Any, Dict
4-
from pydantic import BaseModel
4+
from pydantic import BaseModel, Field
55

66

77
class StatusType(str, Enum):
@@ -91,8 +91,17 @@ class RequestFC(BaseModel):
9191

9292

9393
class ResponseFC(BaseModel):
94+
"""FC result with optional upstream failure context.
95+
96+
``request_id`` and ``body`` retain the original FaaS rejection without
97+
replacing the SDK's existing numeric ``status.code``. The raw ``body``
98+
may contain credentials and is excluded from the model's repr.
99+
"""
100+
94101
status: Status = Status()
95102
output: Optional[Dict[str, Any]] = None
103+
request_id: Optional[str] = None
104+
body: Optional[Dict[str, Any]] = Field(default=None, repr=False)
96105

97106

98107
class RequestTuning(BaseModel):

‎tests/legacy_1x/unit/test_agentic_rl_layer_status.py‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,10 @@ async def test_get_layer_raises_on_region_rejection(monkeypatch):
132132
await FunctionComponentModel().get_layer(LAYER_CODE)
133133

134134
assert "cn-wulanchabu" in str(excinfo.value)
135-
assert excinfo.value.allow_retry is True
136-
assert "Retry the status query" in excinfo.value.solution
135+
assert excinfo.value.allow_retry is False
136+
assert "service owner" in excinfo.value.solution
137+
assert excinfo.value.request_id == LAYER_NOT_FOUND_BODY["request_id"]
138+
assert excinfo.value.body == LAYER_NOT_FOUND_BODY
137139
assert calls["count"] == 1
138140

139141

@@ -235,6 +237,9 @@ async def test_load_reports_server_rejection_with_context(monkeypatch):
235237
assert ENTITY_ID in result.status.message
236238
assert LAYER_CODE in result.status.message
237239
assert "cn-wulanchabu" in result.status.message
240+
assert "Empty instance ID" not in result.status.message
241+
assert result.request_id == LAYER_NOT_FOUND_BODY["request_id"]
242+
assert result.body == LAYER_NOT_FOUND_BODY
238243

239244

240245
async def test_load_succeeds_once_layer_is_ready(monkeypatch):

0 commit comments

Comments
 (0)