Version: 0.9.69.dev.260504
后端: 1. 阶段 4 active-scheduler 服务边界落地,新增 `cmd/active-scheduler`、`services/active_scheduler`、`shared/contracts/activescheduler` 和 active-scheduler port,迁移 dry-run、trigger、preview、confirm zrpc 能力 2. active-scheduler outbox consumer、relay、retry loop 和 due job scanner 迁入独立服务入口,gateway `/active-schedule/*` 改为通过 zrpc client 调用 3. gateway 目录收口为 `gateway/api` + `gateway/client`,统一归档 userauth、notification、active-scheduler 的 HTTP 门面和 zrpc client 4. 将旧 `backend/active_scheduler` 领域核心下沉到 `services/active_scheduler/core`,清退旧根目录活跃实现,并补充 active-scheduler 启动期跨域依赖表检查 5. 调整单体启动与 outbox 归属,`cmd/all` 不再启动 active-scheduler workflow、scanner 或 handler 文档: 1. 更新微服务迁移计划,将阶段 4 active-scheduler 标记为首轮收口完成,并明确下一阶段进入 schedule / task / course / task-class
This commit is contained in:
53
backend/services/active_scheduler/rpc/active_scheduler.proto
Normal file
53
backend/services/active_scheduler/rpc/active_scheduler.proto
Normal file
@@ -0,0 +1,53 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package smartflow.active_scheduler;
|
||||
|
||||
option go_package = "github.com/LoveLosita/smartflow/backend/services/active_scheduler/rpc/pb";
|
||||
|
||||
service ActiveScheduler {
|
||||
rpc DryRun(ActiveScheduleRequest) returns (JSONResponse);
|
||||
rpc Trigger(ActiveScheduleRequest) returns (TriggerResponse);
|
||||
rpc CreatePreview(ActiveScheduleRequest) returns (JSONResponse);
|
||||
rpc GetPreview(GetPreviewRequest) returns (JSONResponse);
|
||||
rpc ConfirmPreview(ConfirmPreviewRequest) returns (JSONResponse);
|
||||
}
|
||||
|
||||
message ActiveScheduleRequest {
|
||||
int64 user_id = 1;
|
||||
string trigger_type = 2;
|
||||
string target_type = 3;
|
||||
int64 target_id = 4;
|
||||
string feedback_id = 5;
|
||||
string idempotency_key = 6;
|
||||
int64 mock_now_unix_nano = 7;
|
||||
bytes payload_json = 8;
|
||||
}
|
||||
|
||||
message GetPreviewRequest {
|
||||
int64 user_id = 1;
|
||||
string preview_id = 2;
|
||||
}
|
||||
|
||||
message ConfirmPreviewRequest {
|
||||
int64 user_id = 1;
|
||||
string preview_id = 2;
|
||||
string candidate_id = 3;
|
||||
string action = 4;
|
||||
bytes edited_changes_json = 5;
|
||||
string idempotency_key = 6;
|
||||
int64 requested_at_unix_nano = 7;
|
||||
string trace_id = 8;
|
||||
}
|
||||
|
||||
message JSONResponse {
|
||||
bytes data_json = 1;
|
||||
}
|
||||
|
||||
message TriggerResponse {
|
||||
string trigger_id = 1;
|
||||
string status = 2;
|
||||
string preview_id = 3;
|
||||
bool has_preview_id = 4;
|
||||
bool dedupe_hit = 5;
|
||||
string trace_id = 6;
|
||||
}
|
||||
122
backend/services/active_scheduler/rpc/errors.go
Normal file
122
backend/services/active_scheduler/rpc/errors.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/LoveLosita/smartflow/backend/respond"
|
||||
activeapply "github.com/LoveLosita/smartflow/backend/services/active_scheduler/core/apply"
|
||||
contracts "github.com/LoveLosita/smartflow/backend/shared/contracts/activescheduler"
|
||||
"google.golang.org/genproto/googleapis/rpc/errdetails"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
activeSchedulerErrorDomain = "smartflow.active_scheduler"
|
||||
activeSchedulerApplyErrorDomain = "smartflow.active_scheduler.apply"
|
||||
)
|
||||
|
||||
// grpcErrorFromServiceError 负责把 active-scheduler 内部错误收口成 gRPC status。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. apply 业务错误保留 error_code,供 gateway 恢复 confirm/apply 的 HTTP 语义;
|
||||
// 2. respond.Response 继续按项目内业务码传输;
|
||||
// 3. 未分类错误只暴露通用内部错误,详细信息留在服务日志。
|
||||
func grpcErrorFromServiceError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if applyErr, ok := activeapply.AsApplyError(err); ok {
|
||||
return grpcErrorFromApplyError(applyErr)
|
||||
}
|
||||
|
||||
var resp respond.Response
|
||||
if errors.As(err, &resp) {
|
||||
return grpcErrorFromResponse(resp)
|
||||
}
|
||||
|
||||
log.Printf("active-scheduler rpc internal error: %v", err)
|
||||
return status.Error(codes.Internal, "active-scheduler service internal error")
|
||||
}
|
||||
|
||||
func grpcErrorFromApplyError(applyErr *activeapply.ApplyError) error {
|
||||
if applyErr == nil {
|
||||
return status.Error(codes.Internal, "active-scheduler apply error")
|
||||
}
|
||||
message := strings.TrimSpace(applyErr.Message)
|
||||
if message == "" {
|
||||
message = string(applyErr.Code)
|
||||
}
|
||||
st := status.New(grpcCodeFromApplyErrorCode(applyErr.Code), message)
|
||||
detail := &errdetails.ErrorInfo{
|
||||
Domain: activeSchedulerApplyErrorDomain,
|
||||
Reason: string(applyErr.Code),
|
||||
Metadata: map[string]string{
|
||||
"info": message,
|
||||
},
|
||||
}
|
||||
withDetails, err := st.WithDetails(detail)
|
||||
if err != nil {
|
||||
return st.Err()
|
||||
}
|
||||
return withDetails.Err()
|
||||
}
|
||||
|
||||
func grpcErrorFromResponse(resp respond.Response) error {
|
||||
code := grpcCodeFromRespondStatus(resp.Status)
|
||||
message := strings.TrimSpace(resp.Info)
|
||||
if message == "" {
|
||||
message = strings.TrimSpace(resp.Status)
|
||||
}
|
||||
st := status.New(code, message)
|
||||
detail := &errdetails.ErrorInfo{
|
||||
Domain: activeSchedulerErrorDomain,
|
||||
Reason: resp.Status,
|
||||
Metadata: map[string]string{
|
||||
"info": resp.Info,
|
||||
},
|
||||
}
|
||||
withDetails, err := st.WithDetails(detail)
|
||||
if err != nil {
|
||||
return st.Err()
|
||||
}
|
||||
return withDetails.Err()
|
||||
}
|
||||
|
||||
func grpcCodeFromApplyErrorCode(code activeapply.ErrorCode) codes.Code {
|
||||
switch contracts.ApplyErrorCode(code) {
|
||||
case contracts.ApplyErrorCodeForbidden:
|
||||
return codes.PermissionDenied
|
||||
case contracts.ApplyErrorCodeTargetNotFound:
|
||||
return codes.NotFound
|
||||
case contracts.ApplyErrorCodeDBError:
|
||||
return codes.Internal
|
||||
case contracts.ApplyErrorCodeExpired,
|
||||
contracts.ApplyErrorCodeIdempotencyConflict,
|
||||
contracts.ApplyErrorCodeBaseVersionChanged,
|
||||
contracts.ApplyErrorCodeTargetCompleted,
|
||||
contracts.ApplyErrorCodeTargetAlreadySchedule,
|
||||
contracts.ApplyErrorCodeSlotConflict,
|
||||
contracts.ApplyErrorCodeAlreadyApplied:
|
||||
return codes.FailedPrecondition
|
||||
default:
|
||||
return codes.InvalidArgument
|
||||
}
|
||||
}
|
||||
|
||||
func grpcCodeFromRespondStatus(statusValue string) codes.Code {
|
||||
switch strings.TrimSpace(statusValue) {
|
||||
case respond.MissingToken.Status, respond.InvalidToken.Status, respond.InvalidClaims.Status,
|
||||
respond.ErrUnauthorized.Status, respond.WrongTokenType.Status, respond.UserLoggedOut.Status:
|
||||
return codes.Unauthenticated
|
||||
case respond.MissingParam.Status, respond.WrongParamType.Status, respond.ParamTooLong.Status:
|
||||
return codes.InvalidArgument
|
||||
}
|
||||
|
||||
if strings.HasPrefix(strings.TrimSpace(statusValue), "5") {
|
||||
return codes.Internal
|
||||
}
|
||||
return codes.InvalidArgument
|
||||
}
|
||||
155
backend/services/active_scheduler/rpc/handler.go
Normal file
155
backend/services/active_scheduler/rpc/handler.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/LoveLosita/smartflow/backend/respond"
|
||||
"github.com/LoveLosita/smartflow/backend/services/active_scheduler/rpc/pb"
|
||||
activeschedulersv "github.com/LoveLosita/smartflow/backend/services/active_scheduler/sv"
|
||||
contracts "github.com/LoveLosita/smartflow/backend/shared/contracts/activescheduler"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
pb.UnimplementedActiveSchedulerServer
|
||||
svc *activeschedulersv.Service
|
||||
}
|
||||
|
||||
func NewHandler(svc *activeschedulersv.Service) *Handler {
|
||||
return &Handler{svc: svc}
|
||||
}
|
||||
|
||||
// DryRun 负责把 gRPC 请求转换为主动调度 dry-run 服务调用。
|
||||
func (h *Handler) DryRun(ctx context.Context, req *pb.ActiveScheduleRequest) (*pb.JSONResponse, error) {
|
||||
if h == nil || h.svc == nil {
|
||||
return nil, grpcErrorFromServiceError(errors.New("active-scheduler service dependency not initialized"))
|
||||
}
|
||||
if req == nil {
|
||||
return nil, grpcErrorFromServiceError(respond.MissingParam)
|
||||
}
|
||||
data, err := h.svc.DryRun(ctx, activeScheduleRequestFromPB(req))
|
||||
if err != nil {
|
||||
return nil, grpcErrorFromServiceError(err)
|
||||
}
|
||||
return jsonResponse(data), nil
|
||||
}
|
||||
|
||||
func (h *Handler) Trigger(ctx context.Context, req *pb.ActiveScheduleRequest) (*pb.TriggerResponse, error) {
|
||||
if h == nil || h.svc == nil {
|
||||
return nil, grpcErrorFromServiceError(errors.New("active-scheduler service dependency not initialized"))
|
||||
}
|
||||
if req == nil {
|
||||
return nil, grpcErrorFromServiceError(respond.MissingParam)
|
||||
}
|
||||
resp, err := h.svc.Trigger(ctx, activeScheduleRequestFromPB(req))
|
||||
if err != nil {
|
||||
return nil, grpcErrorFromServiceError(err)
|
||||
}
|
||||
return triggerResponseToPB(resp), nil
|
||||
}
|
||||
|
||||
func (h *Handler) CreatePreview(ctx context.Context, req *pb.ActiveScheduleRequest) (*pb.JSONResponse, error) {
|
||||
if h == nil || h.svc == nil {
|
||||
return nil, grpcErrorFromServiceError(errors.New("active-scheduler service dependency not initialized"))
|
||||
}
|
||||
if req == nil {
|
||||
return nil, grpcErrorFromServiceError(respond.MissingParam)
|
||||
}
|
||||
data, err := h.svc.CreatePreview(ctx, activeScheduleRequestFromPB(req))
|
||||
if err != nil {
|
||||
return nil, grpcErrorFromServiceError(err)
|
||||
}
|
||||
return jsonResponse(data), nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreview(ctx context.Context, req *pb.GetPreviewRequest) (*pb.JSONResponse, error) {
|
||||
if h == nil || h.svc == nil {
|
||||
return nil, grpcErrorFromServiceError(errors.New("active-scheduler service dependency not initialized"))
|
||||
}
|
||||
if req == nil {
|
||||
return nil, grpcErrorFromServiceError(respond.MissingParam)
|
||||
}
|
||||
data, err := h.svc.GetPreview(ctx, contracts.GetPreviewRequest{
|
||||
UserID: int(req.UserId),
|
||||
PreviewID: req.PreviewId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, grpcErrorFromServiceError(err)
|
||||
}
|
||||
return jsonResponse(data), nil
|
||||
}
|
||||
|
||||
func (h *Handler) ConfirmPreview(ctx context.Context, req *pb.ConfirmPreviewRequest) (*pb.JSONResponse, error) {
|
||||
if h == nil || h.svc == nil {
|
||||
return nil, grpcErrorFromServiceError(errors.New("active-scheduler service dependency not initialized"))
|
||||
}
|
||||
if req == nil {
|
||||
return nil, grpcErrorFromServiceError(respond.MissingParam)
|
||||
}
|
||||
data, err := h.svc.ConfirmPreview(ctx, confirmRequestFromPB(req))
|
||||
if err != nil {
|
||||
return nil, grpcErrorFromServiceError(err)
|
||||
}
|
||||
return jsonResponse(data), nil
|
||||
}
|
||||
|
||||
func activeScheduleRequestFromPB(req *pb.ActiveScheduleRequest) contracts.ActiveScheduleRequest {
|
||||
var mockNow *time.Time
|
||||
if req.MockNowUnixNano > 0 {
|
||||
value := time.Unix(0, req.MockNowUnixNano)
|
||||
mockNow = &value
|
||||
}
|
||||
return contracts.ActiveScheduleRequest{
|
||||
UserID: int(req.UserId),
|
||||
TriggerType: req.TriggerType,
|
||||
TargetType: req.TargetType,
|
||||
TargetID: int(req.TargetId),
|
||||
FeedbackID: req.FeedbackId,
|
||||
IdempotencyKey: req.IdempotencyKey,
|
||||
MockNow: mockNow,
|
||||
Payload: json.RawMessage(req.PayloadJson),
|
||||
}
|
||||
}
|
||||
|
||||
func confirmRequestFromPB(req *pb.ConfirmPreviewRequest) contracts.ConfirmPreviewRequest {
|
||||
requestedAt := time.Time{}
|
||||
if req.RequestedAtUnixNano > 0 {
|
||||
requestedAt = time.Unix(0, req.RequestedAtUnixNano)
|
||||
}
|
||||
return contracts.ConfirmPreviewRequest{
|
||||
UserID: int(req.UserId),
|
||||
PreviewID: req.PreviewId,
|
||||
CandidateID: req.CandidateId,
|
||||
Action: req.Action,
|
||||
EditedChanges: json.RawMessage(req.EditedChangesJson),
|
||||
IdempotencyKey: req.IdempotencyKey,
|
||||
RequestedAt: requestedAt,
|
||||
TraceID: req.TraceId,
|
||||
}
|
||||
}
|
||||
|
||||
func triggerResponseToPB(resp *contracts.TriggerResponse) *pb.TriggerResponse {
|
||||
if resp == nil {
|
||||
return &pb.TriggerResponse{}
|
||||
}
|
||||
previewID := ""
|
||||
hasPreviewID := false
|
||||
if resp.PreviewID != nil {
|
||||
previewID = *resp.PreviewID
|
||||
hasPreviewID = previewID != ""
|
||||
}
|
||||
return &pb.TriggerResponse{
|
||||
TriggerId: resp.TriggerID,
|
||||
Status: resp.Status,
|
||||
PreviewId: previewID,
|
||||
HasPreviewId: hasPreviewID,
|
||||
DedupeHit: resp.DedupeHit,
|
||||
TraceId: resp.TraceID,
|
||||
}
|
||||
}
|
||||
|
||||
func jsonResponse(data json.RawMessage) *pb.JSONResponse {
|
||||
return &pb.JSONResponse{DataJson: []byte(data)}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package pb
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
|
||||
var _ = proto.Marshal
|
||||
|
||||
const _ = proto.ProtoPackageIsVersion3
|
||||
|
||||
type ActiveScheduleRequest struct {
|
||||
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
TriggerType string `protobuf:"bytes,2,opt,name=trigger_type,json=triggerType,proto3" json:"trigger_type,omitempty"`
|
||||
TargetType string `protobuf:"bytes,3,opt,name=target_type,json=targetType,proto3" json:"target_type,omitempty"`
|
||||
TargetId int64 `protobuf:"varint,4,opt,name=target_id,json=targetId,proto3" json:"target_id,omitempty"`
|
||||
FeedbackId string `protobuf:"bytes,5,opt,name=feedback_id,json=feedbackId,proto3" json:"feedback_id,omitempty"`
|
||||
IdempotencyKey string `protobuf:"bytes,6,opt,name=idempotency_key,json=idempotencyKey,proto3" json:"idempotency_key,omitempty"`
|
||||
MockNowUnixNano int64 `protobuf:"varint,7,opt,name=mock_now_unix_nano,json=mockNowUnixNano,proto3" json:"mock_now_unix_nano,omitempty"`
|
||||
PayloadJson []byte `protobuf:"bytes,8,opt,name=payload_json,json=payloadJson,proto3" json:"payload_json,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ActiveScheduleRequest) Reset() { *m = ActiveScheduleRequest{} }
|
||||
func (m *ActiveScheduleRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ActiveScheduleRequest) ProtoMessage() {}
|
||||
|
||||
type GetPreviewRequest struct {
|
||||
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
PreviewId string `protobuf:"bytes,2,opt,name=preview_id,json=previewId,proto3" json:"preview_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GetPreviewRequest) Reset() { *m = GetPreviewRequest{} }
|
||||
func (m *GetPreviewRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetPreviewRequest) ProtoMessage() {}
|
||||
|
||||
type ConfirmPreviewRequest struct {
|
||||
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
PreviewId string `protobuf:"bytes,2,opt,name=preview_id,json=previewId,proto3" json:"preview_id,omitempty"`
|
||||
CandidateId string `protobuf:"bytes,3,opt,name=candidate_id,json=candidateId,proto3" json:"candidate_id,omitempty"`
|
||||
Action string `protobuf:"bytes,4,opt,name=action,proto3" json:"action,omitempty"`
|
||||
EditedChangesJson []byte `protobuf:"bytes,5,opt,name=edited_changes_json,json=editedChangesJson,proto3" json:"edited_changes_json,omitempty"`
|
||||
IdempotencyKey string `protobuf:"bytes,6,opt,name=idempotency_key,json=idempotencyKey,proto3" json:"idempotency_key,omitempty"`
|
||||
RequestedAtUnixNano int64 `protobuf:"varint,7,opt,name=requested_at_unix_nano,json=requestedAtUnixNano,proto3" json:"requested_at_unix_nano,omitempty"`
|
||||
TraceId string `protobuf:"bytes,8,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ConfirmPreviewRequest) Reset() { *m = ConfirmPreviewRequest{} }
|
||||
func (m *ConfirmPreviewRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ConfirmPreviewRequest) ProtoMessage() {}
|
||||
|
||||
type JSONResponse struct {
|
||||
DataJson []byte `protobuf:"bytes,1,opt,name=data_json,json=dataJson,proto3" json:"data_json,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *JSONResponse) Reset() { *m = JSONResponse{} }
|
||||
func (m *JSONResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*JSONResponse) ProtoMessage() {}
|
||||
|
||||
type TriggerResponse struct {
|
||||
TriggerId string `protobuf:"bytes,1,opt,name=trigger_id,json=triggerId,proto3" json:"trigger_id,omitempty"`
|
||||
Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
|
||||
PreviewId string `protobuf:"bytes,3,opt,name=preview_id,json=previewId,proto3" json:"preview_id,omitempty"`
|
||||
HasPreviewId bool `protobuf:"varint,4,opt,name=has_preview_id,json=hasPreviewId,proto3" json:"has_preview_id,omitempty"`
|
||||
DedupeHit bool `protobuf:"varint,5,opt,name=dedupe_hit,json=dedupeHit,proto3" json:"dedupe_hit,omitempty"`
|
||||
TraceId string `protobuf:"bytes,6,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *TriggerResponse) Reset() { *m = TriggerResponse{} }
|
||||
func (m *TriggerResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*TriggerResponse) ProtoMessage() {}
|
||||
@@ -0,0 +1,201 @@
|
||||
package pb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
ActiveScheduler_DryRun_FullMethodName = "/smartflow.active_scheduler.ActiveScheduler/DryRun"
|
||||
ActiveScheduler_Trigger_FullMethodName = "/smartflow.active_scheduler.ActiveScheduler/Trigger"
|
||||
ActiveScheduler_CreatePreview_FullMethodName = "/smartflow.active_scheduler.ActiveScheduler/CreatePreview"
|
||||
ActiveScheduler_GetPreview_FullMethodName = "/smartflow.active_scheduler.ActiveScheduler/GetPreview"
|
||||
ActiveScheduler_ConfirmPreview_FullMethodName = "/smartflow.active_scheduler.ActiveScheduler/ConfirmPreview"
|
||||
)
|
||||
|
||||
type ActiveSchedulerClient interface {
|
||||
DryRun(ctx context.Context, in *ActiveScheduleRequest, opts ...grpc.CallOption) (*JSONResponse, error)
|
||||
Trigger(ctx context.Context, in *ActiveScheduleRequest, opts ...grpc.CallOption) (*TriggerResponse, error)
|
||||
CreatePreview(ctx context.Context, in *ActiveScheduleRequest, opts ...grpc.CallOption) (*JSONResponse, error)
|
||||
GetPreview(ctx context.Context, in *GetPreviewRequest, opts ...grpc.CallOption) (*JSONResponse, error)
|
||||
ConfirmPreview(ctx context.Context, in *ConfirmPreviewRequest, opts ...grpc.CallOption) (*JSONResponse, error)
|
||||
}
|
||||
|
||||
type activeSchedulerClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewActiveSchedulerClient(cc grpc.ClientConnInterface) ActiveSchedulerClient {
|
||||
return &activeSchedulerClient{cc}
|
||||
}
|
||||
|
||||
func (c *activeSchedulerClient) DryRun(ctx context.Context, in *ActiveScheduleRequest, opts ...grpc.CallOption) (*JSONResponse, error) {
|
||||
out := new(JSONResponse)
|
||||
err := c.cc.Invoke(ctx, ActiveScheduler_DryRun_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *activeSchedulerClient) Trigger(ctx context.Context, in *ActiveScheduleRequest, opts ...grpc.CallOption) (*TriggerResponse, error) {
|
||||
out := new(TriggerResponse)
|
||||
err := c.cc.Invoke(ctx, ActiveScheduler_Trigger_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *activeSchedulerClient) CreatePreview(ctx context.Context, in *ActiveScheduleRequest, opts ...grpc.CallOption) (*JSONResponse, error) {
|
||||
out := new(JSONResponse)
|
||||
err := c.cc.Invoke(ctx, ActiveScheduler_CreatePreview_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *activeSchedulerClient) GetPreview(ctx context.Context, in *GetPreviewRequest, opts ...grpc.CallOption) (*JSONResponse, error) {
|
||||
out := new(JSONResponse)
|
||||
err := c.cc.Invoke(ctx, ActiveScheduler_GetPreview_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *activeSchedulerClient) ConfirmPreview(ctx context.Context, in *ConfirmPreviewRequest, opts ...grpc.CallOption) (*JSONResponse, error) {
|
||||
out := new(JSONResponse)
|
||||
err := c.cc.Invoke(ctx, ActiveScheduler_ConfirmPreview_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type ActiveSchedulerServer interface {
|
||||
DryRun(context.Context, *ActiveScheduleRequest) (*JSONResponse, error)
|
||||
Trigger(context.Context, *ActiveScheduleRequest) (*TriggerResponse, error)
|
||||
CreatePreview(context.Context, *ActiveScheduleRequest) (*JSONResponse, error)
|
||||
GetPreview(context.Context, *GetPreviewRequest) (*JSONResponse, error)
|
||||
ConfirmPreview(context.Context, *ConfirmPreviewRequest) (*JSONResponse, error)
|
||||
}
|
||||
|
||||
type UnimplementedActiveSchedulerServer struct{}
|
||||
|
||||
func (UnimplementedActiveSchedulerServer) DryRun(context.Context, *ActiveScheduleRequest) (*JSONResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DryRun not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedActiveSchedulerServer) Trigger(context.Context, *ActiveScheduleRequest) (*TriggerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Trigger not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedActiveSchedulerServer) CreatePreview(context.Context, *ActiveScheduleRequest) (*JSONResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreatePreview not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedActiveSchedulerServer) GetPreview(context.Context, *GetPreviewRequest) (*JSONResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPreview not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedActiveSchedulerServer) ConfirmPreview(context.Context, *ConfirmPreviewRequest) (*JSONResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConfirmPreview not implemented")
|
||||
}
|
||||
|
||||
func RegisterActiveSchedulerServer(s grpc.ServiceRegistrar, srv ActiveSchedulerServer) {
|
||||
s.RegisterService(&ActiveScheduler_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ActiveScheduler_DryRun_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ActiveScheduleRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ActiveSchedulerServer).DryRun(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: ActiveScheduler_DryRun_FullMethodName}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ActiveSchedulerServer).DryRun(ctx, req.(*ActiveScheduleRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ActiveScheduler_Trigger_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ActiveScheduleRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ActiveSchedulerServer).Trigger(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: ActiveScheduler_Trigger_FullMethodName}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ActiveSchedulerServer).Trigger(ctx, req.(*ActiveScheduleRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ActiveScheduler_CreatePreview_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ActiveScheduleRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ActiveSchedulerServer).CreatePreview(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: ActiveScheduler_CreatePreview_FullMethodName}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ActiveSchedulerServer).CreatePreview(ctx, req.(*ActiveScheduleRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ActiveScheduler_GetPreview_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetPreviewRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ActiveSchedulerServer).GetPreview(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: ActiveScheduler_GetPreview_FullMethodName}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ActiveSchedulerServer).GetPreview(ctx, req.(*GetPreviewRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ActiveScheduler_ConfirmPreview_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ConfirmPreviewRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ActiveSchedulerServer).ConfirmPreview(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: ActiveScheduler_ConfirmPreview_FullMethodName}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ActiveSchedulerServer).ConfirmPreview(ctx, req.(*ConfirmPreviewRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var ActiveScheduler_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "smartflow.active_scheduler.ActiveScheduler",
|
||||
HandlerType: (*ActiveSchedulerServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{MethodName: "DryRun", Handler: _ActiveScheduler_DryRun_Handler},
|
||||
{MethodName: "Trigger", Handler: _ActiveScheduler_Trigger_Handler},
|
||||
{MethodName: "CreatePreview", Handler: _ActiveScheduler_CreatePreview_Handler},
|
||||
{MethodName: "GetPreview", Handler: _ActiveScheduler_GetPreview_Handler},
|
||||
{MethodName: "ConfirmPreview", Handler: _ActiveScheduler_ConfirmPreview_Handler},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "services/active_scheduler/rpc/active_scheduler.proto",
|
||||
}
|
||||
60
backend/services/active_scheduler/rpc/server.go
Normal file
60
backend/services/active_scheduler/rpc/server.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/LoveLosita/smartflow/backend/services/active_scheduler/rpc/pb"
|
||||
activeschedulersv "github.com/LoveLosita/smartflow/backend/services/active_scheduler/sv"
|
||||
"github.com/zeromicro/go-zero/core/service"
|
||||
"github.com/zeromicro/go-zero/zrpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultListenOn = "0.0.0.0:9083"
|
||||
defaultTimeout = 8 * time.Second
|
||||
)
|
||||
|
||||
type ServerOptions struct {
|
||||
ListenOn string
|
||||
Timeout time.Duration
|
||||
Service *activeschedulersv.Service
|
||||
}
|
||||
|
||||
// NewServer 创建 active-scheduler zrpc 服务端。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 只负责 zrpc server 配置与 gRPC handler 注册;
|
||||
// 2. 不创建数据库、LLM、outbox 或 worker,它们由 cmd/active-scheduler 管理;
|
||||
// 3. 返回 listenOn 供进程入口打印启动日志。
|
||||
func NewServer(opts ServerOptions) (*zrpc.RpcServer, string, error) {
|
||||
if opts.Service == nil {
|
||||
return nil, "", errors.New("active-scheduler service dependency not initialized")
|
||||
}
|
||||
|
||||
listenOn := strings.TrimSpace(opts.ListenOn)
|
||||
if listenOn == "" {
|
||||
listenOn = defaultListenOn
|
||||
}
|
||||
timeout := opts.Timeout
|
||||
if timeout <= 0 {
|
||||
timeout = defaultTimeout
|
||||
}
|
||||
|
||||
server, err := zrpc.NewServer(zrpc.RpcServerConf{
|
||||
ServiceConf: service.ServiceConf{
|
||||
Name: "active-scheduler.rpc",
|
||||
Mode: service.DevMode,
|
||||
},
|
||||
ListenOn: listenOn,
|
||||
Timeout: int64(timeout / time.Millisecond),
|
||||
}, func(grpcServer *grpc.Server) {
|
||||
pb.RegisterActiveSchedulerServer(grpcServer, NewHandler(opts.Service))
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return server, listenOn, nil
|
||||
}
|
||||
Reference in New Issue
Block a user