115 lines
3.6 KiB
Go
115 lines
3.6 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"time"
|
||
|
||
"gcy_hpc_server/internal/model"
|
||
"gcy_hpc_server/internal/store"
|
||
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// ApplicationService handles parameter validation, script rendering, and job
|
||
// submission for parameterized HPC applications.
|
||
type ApplicationService struct {
|
||
store *store.ApplicationStore
|
||
jobSvc *JobService
|
||
workDirBase string
|
||
logger *zap.Logger
|
||
taskSvc *TaskService
|
||
}
|
||
|
||
func NewApplicationService(store *store.ApplicationStore, jobSvc *JobService, workDirBase string, logger *zap.Logger, taskSvc ...*TaskService) *ApplicationService {
|
||
var ts *TaskService
|
||
if len(taskSvc) > 0 {
|
||
ts = taskSvc[0]
|
||
}
|
||
return &ApplicationService{store: store, jobSvc: jobSvc, workDirBase: workDirBase, logger: logger, taskSvc: ts}
|
||
}
|
||
|
||
// ListApplications delegates to the store.
|
||
func (s *ApplicationService) ListApplications(ctx context.Context, page, pageSize int) ([]model.Application, int, error) {
|
||
return s.store.List(ctx, page, pageSize)
|
||
}
|
||
|
||
// CreateApplication delegates to the store.
|
||
func (s *ApplicationService) CreateApplication(ctx context.Context, req *model.CreateApplicationRequest) (int64, error) {
|
||
return s.store.Create(ctx, req)
|
||
}
|
||
|
||
// GetApplication delegates to the store.
|
||
func (s *ApplicationService) GetApplication(ctx context.Context, id int64) (*model.Application, error) {
|
||
return s.store.GetByID(ctx, id)
|
||
}
|
||
|
||
// UpdateApplication delegates to the store.
|
||
func (s *ApplicationService) UpdateApplication(ctx context.Context, id int64, req *model.UpdateApplicationRequest) error {
|
||
return s.store.Update(ctx, id, req)
|
||
}
|
||
|
||
// DeleteApplication delegates to the store.
|
||
func (s *ApplicationService) DeleteApplication(ctx context.Context, id int64) error {
|
||
return s.store.Delete(ctx, id)
|
||
}
|
||
|
||
// SubmitFromApplication orchestrates the full submission flow.
|
||
// When TaskService is available, it delegates to ProcessTaskSync which creates
|
||
// an hpc_tasks record and runs the full pipeline. Otherwise falls back to the
|
||
// original direct implementation.
|
||
func (s *ApplicationService) SubmitFromApplication(ctx context.Context, applicationID int64, values map[string]string) (*model.JobResponse, error) {
|
||
if s.taskSvc != nil {
|
||
req := &model.CreateTaskRequest{
|
||
AppID: applicationID,
|
||
Values: values,
|
||
InputFileIDs: nil, // old API has no file_ids concept
|
||
TaskName: "",
|
||
}
|
||
return s.taskSvc.ProcessTaskSync(ctx, req)
|
||
}
|
||
|
||
// Fallback: original direct logic when TaskService not available
|
||
app, err := s.store.GetByID(ctx, applicationID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("get application: %w", err)
|
||
}
|
||
if app == nil {
|
||
return nil, fmt.Errorf("application %d not found", applicationID)
|
||
}
|
||
|
||
var params []model.ParameterSchema
|
||
if len(app.Parameters) > 0 {
|
||
if err := json.Unmarshal(app.Parameters, ¶ms); err != nil {
|
||
return nil, fmt.Errorf("parse parameters: %w", err)
|
||
}
|
||
}
|
||
|
||
if err := ValidateParams(params, values); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
rendered := RenderScript(app.ScriptTemplate, params, values)
|
||
|
||
workDir := ""
|
||
if s.workDirBase != "" {
|
||
safeName := SanitizeDirName(app.Name)
|
||
subDir := time.Now().Format("20060102_150405") + "_" + RandomSuffix(4)
|
||
workDir = filepath.Join(s.workDirBase, safeName, subDir)
|
||
if err := os.MkdirAll(workDir, 0777); err != nil {
|
||
return nil, fmt.Errorf("create work directory %s: %w", workDir, err)
|
||
}
|
||
// 绕过 umask,确保整条路径都有写权限
|
||
for dir := workDir; dir != s.workDirBase; dir = filepath.Dir(dir) {
|
||
os.Chmod(dir, 0777)
|
||
}
|
||
os.Chmod(s.workDirBase, 0777)
|
||
}
|
||
|
||
req := &model.SubmitJobRequest{Script: rendered, WorkDir: workDir}
|
||
return s.jobSvc.SubmitJob(ctx, req)
|
||
}
|