mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-05 10:12:59 +00:00
feat(task): replace built-in task adaptors with a sandboxed JS plugin system (#7076)
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/QuantumNous/new-api/dto"
|
||||
"github.com/QuantumNous/new-api/logger"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
pluginruntime "github.com/QuantumNous/new-api/pkg/jsplugin"
|
||||
"github.com/QuantumNous/new-api/relay"
|
||||
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// taskPluginSubmitDiagnostics keeps plugin-only lifecycle logging out of the
|
||||
// ordinary task path. An empty plugin key makes every method a no-op.
|
||||
type taskPluginSubmitDiagnostics struct {
|
||||
context *gin.Context
|
||||
pluginKey string
|
||||
generation uint64
|
||||
}
|
||||
|
||||
func newTaskPluginSubmitDiagnostics(c *gin.Context) taskPluginSubmitDiagnostics {
|
||||
diagnostics := taskPluginSubmitDiagnostics{
|
||||
context: c,
|
||||
pluginKey: c.GetString("expected_task_plugin_key"),
|
||||
}
|
||||
if diagnostics.pluginKey == "" {
|
||||
return diagnostics
|
||||
}
|
||||
if pinnedValue, exists := c.Get(pluginruntime.ContextKeyPinnedPlugin); exists {
|
||||
if pinned, ok := pinnedValue.(pluginruntime.PinnedPlugin); ok && pinned.Generation != nil {
|
||||
diagnostics.generation = pinned.Generation.Number
|
||||
}
|
||||
}
|
||||
return diagnostics
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) start(info *relaycommon.RelayInfo) {
|
||||
if d.pluginKey == "" {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=start generation=%d plugin=%q model=%q action_present=%t",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
info.OriginModelName,
|
||||
info.Action != "",
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) refund(stage string) {
|
||||
if d.pluginKey == "" {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=refund_invoked generation=%d plugin=%q stage=%q durable=false",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
stage,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) cancelled(stage string, attempt int) {
|
||||
if d.pluginKey == "" {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=cancelled generation=%d plugin=%q stage=%q attempt=%d",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
stage,
|
||||
attempt,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) attempt(attempt int, channel *model.Channel, locked bool) {
|
||||
if d.pluginKey == "" || channel == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=attempt generation=%d plugin=%q attempt=%d channel_id=%d channel_type=%d locked=%t",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
attempt,
|
||||
channel.Id,
|
||||
channel.Type,
|
||||
locked,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) attemptSucceeded(attempt int, result *relay.TaskSubmitResult) {
|
||||
if d.pluginKey == "" || result == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=attempt_succeeded generation=%d plugin=%q attempt=%d platform=%q quota=%d task_data_bytes=%d client_response=%t immediate=%t",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
attempt,
|
||||
result.Platform,
|
||||
result.Quota,
|
||||
len(result.TaskData),
|
||||
result.ClientResponse != nil,
|
||||
result.Immediate != nil,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) attemptFailed(attempt int, channel *model.Channel, taskErr *dto.TaskError, willRetry bool) {
|
||||
if d.pluginKey == "" || channel == nil || taskErr == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=attempt_failed generation=%d plugin=%q attempt=%d channel_id=%d channel_type=%d code=%q status=%d local=%t will_retry=%t",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
attempt,
|
||||
channel.Id,
|
||||
channel.Type,
|
||||
taskErr.Code,
|
||||
taskErr.StatusCode,
|
||||
taskErr.LocalError,
|
||||
willRetry,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) failed(stage, reason string, taskErr *dto.TaskError, durable bool) {
|
||||
if d.pluginKey == "" {
|
||||
return
|
||||
}
|
||||
code := ""
|
||||
status := 0
|
||||
local := true
|
||||
if taskErr != nil {
|
||||
code = taskErr.Code
|
||||
status = taskErr.StatusCode
|
||||
local = taskErr.LocalError
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=failed generation=%d plugin=%q stage=%q reason=%q code=%q status=%d local=%t durable=%t",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
stage,
|
||||
reason,
|
||||
code,
|
||||
status,
|
||||
local,
|
||||
durable,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) reserve(event string, quota int) {
|
||||
if d.pluginKey == "" {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=%s generation=%d plugin=%q quota=%d",
|
||||
event,
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
quota,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) insertStart(task *model.Task) {
|
||||
if d.pluginKey == "" || task == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=insert_start generation=%d plugin=%q public_task_id=%q platform=%q channel_id=%d quota=%d",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
task.TaskID,
|
||||
task.Platform,
|
||||
task.ChannelId,
|
||||
task.Quota,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) durable(task *model.Task) {
|
||||
if d.pluginKey == "" || task == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=durable generation=%d plugin=%q public_task_id=%q status=%q durable=true",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
task.TaskID,
|
||||
taskPluginDebugStatus(string(task.Status)),
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) settleStart(task *model.Task, quota int) {
|
||||
if d.pluginKey == "" || task == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=settle_start generation=%d plugin=%q public_task_id=%q quota=%d durable=true",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
task.TaskID,
|
||||
quota,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) complete(task *model.Task, quota int) {
|
||||
if d.pluginKey == "" || task == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=complete generation=%d plugin=%q public_task_id=%q quota=%d durable=true",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
task.TaskID,
|
||||
quota,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) present(task *model.Task, presenter string) {
|
||||
if d.pluginKey == "" || task == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=present generation=%d plugin=%q public_task_id=%q presenter=%q durable=true",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
task.TaskID,
|
||||
presenter,
|
||||
)
|
||||
}
|
||||
|
||||
func (d taskPluginSubmitDiagnostics) presentError(taskErr *dto.TaskError) {
|
||||
if d.pluginKey == "" || taskErr == nil {
|
||||
return
|
||||
}
|
||||
logger.LogDebug(
|
||||
d.context,
|
||||
"task_plugin subsystem=submit event=present_error generation=%d plugin=%q code=%q status=%d local=%t",
|
||||
d.generation,
|
||||
d.pluginKey,
|
||||
taskErr.Code,
|
||||
taskErr.StatusCode,
|
||||
taskErr.LocalError,
|
||||
)
|
||||
}
|
||||
|
||||
func taskPluginDebugStatus(status string) string {
|
||||
switch model.TaskStatus(status) {
|
||||
case model.TaskStatusSubmitted,
|
||||
model.TaskStatusQueued,
|
||||
model.TaskStatusInProgress,
|
||||
model.TaskStatusSuccess,
|
||||
model.TaskStatusFailure:
|
||||
return status
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user