Files
hpc/internal/service/application_service.go

115 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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, &params); 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)
}