fix
This commit is contained in:
+162
-1
@@ -1,7 +1,17 @@
|
||||
package control_case
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"control/analize"
|
||||
"github.com/che4web/go4rest"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -11,8 +21,11 @@ type ControlCaseController struct {
|
||||
}
|
||||
|
||||
func NewControlCaseController(db *gorm.DB) *ControlCaseController {
|
||||
viewSet := go4rest.NewViewSet[ControlCase](db)
|
||||
viewSet.PreloadField = []string{"Params"}
|
||||
|
||||
return &ControlCaseController{
|
||||
ViewSet: go4rest.NewViewSet[ControlCase](db),
|
||||
ViewSet: viewSet,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
@@ -28,3 +41,151 @@ func NewParamsController(db *gorm.DB) *ParamsController {
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type LaunchControlCaseRequest struct {
|
||||
ParamsID uint `json:"params_id" binding:"required"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) Launch(ctx *gin.Context) {
|
||||
var req LaunchControlCaseRequest
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var params Params
|
||||
if err := c.db.First(¶ms, req.ParamsID).Error; err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "params not found"})
|
||||
return
|
||||
}
|
||||
|
||||
name := req.Name
|
||||
if strings.TrimSpace(name) == "" {
|
||||
name = fmt.Sprintf("case-%d", params.ID)
|
||||
}
|
||||
|
||||
controlCase := ControlCase{
|
||||
Name: name,
|
||||
ParamsID: params.ID,
|
||||
Status: "N",
|
||||
}
|
||||
if err := c.db.Create(&controlCase).Error; err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.db.Preload("Params").First(&controlCase, controlCase.ID).Error; err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusCreated, controlCase)
|
||||
}
|
||||
|
||||
type CSVSeriesResponse struct {
|
||||
Columns []string `json:"columns"`
|
||||
Rows [][]interface{} `json:"rows"`
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) ChartData(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var controlCase ControlCase
|
||||
if err := c.db.Preload("Params").First(&controlCase, id).Error; err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "record not found"})
|
||||
return
|
||||
}
|
||||
|
||||
csvPath := filepath.Join(".", strconv.FormatUint(uint64(controlCase.ParamsID), 10), "foo.csv")
|
||||
file, err := os.Open(csvPath)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "csv file not found"})
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
reader := csv.NewReader(file)
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if len(records) == 0 {
|
||||
ctx.JSON(http.StatusOK, CSVSeriesResponse{Columns: []string{}, Rows: [][]interface{}{}})
|
||||
return
|
||||
}
|
||||
|
||||
columns := records[0]
|
||||
rows := make([][]interface{}, 0, len(records)-1)
|
||||
for _, record := range records[1:] {
|
||||
row := make([]interface{}, 0, len(record))
|
||||
for _, value := range record {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if f, err := strconv.ParseFloat(trimmed, 64); err == nil {
|
||||
row = append(row, f)
|
||||
} else {
|
||||
row = append(row, trimmed)
|
||||
}
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, CSVSeriesResponse{Columns: columns, Rows: rows})
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) RecalculateAnalysis(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var controlCase ControlCase
|
||||
if err := c.db.First(&controlCase, id).Error; err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "record not found"})
|
||||
return
|
||||
}
|
||||
|
||||
csvPath := filepath.Join(".", strconv.FormatUint(uint64(controlCase.ParamsID), 10), "foo.csv")
|
||||
result, err := analize.AnalyzeCSV(c.db, controlCase.ID, controlCase.Name, csvPath)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) FieldMap(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
timeValue, err := strconv.ParseFloat(ctx.Query("time"), 64)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid time"})
|
||||
return
|
||||
}
|
||||
|
||||
var controlCase ControlCase
|
||||
if err := c.db.First(&controlCase, id).Error; err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "record not found"})
|
||||
return
|
||||
}
|
||||
|
||||
h5Path := filepath.Join(".", strconv.FormatUint(uint64(controlCase.ParamsID), 10), "storage.h5")
|
||||
result, err := ReadNearestFieldMap(h5Path, timeValue)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
package control_case
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FieldMapResponse struct {
|
||||
RequestedT float64 `json:"requested_t"`
|
||||
StageT float64 `json:"stage_t"`
|
||||
Rows int `json:"rows"`
|
||||
Cols int `json:"cols"`
|
||||
Fields map[string][][]float64 `json:"fields"`
|
||||
}
|
||||
|
||||
var (
|
||||
stagePathRe = regexp.MustCompile(`^\s*group\s+/map/(stage_t=[^\s]+)\s*$`)
|
||||
dimsRe = regexp.MustCompile(`\(\s*(\d+)\s*,\s*(\d+)\s*\)`)
|
||||
floatInDataRe = regexp.MustCompile(`[-+]?(?:\d*\.\d+|\d+\.?\d*)(?:[eE][-+]?\d+)?`)
|
||||
)
|
||||
|
||||
func ReadNearestFieldMap(filePath string, requestedT float64) (*FieldMapResponse, error) {
|
||||
stageGroups, err := listStageGroups(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(stageGroups) == 0 {
|
||||
return nil, fmt.Errorf("no stage_t groups found")
|
||||
}
|
||||
|
||||
selected := stageGroups[0]
|
||||
for _, stage := range stageGroups[1:] {
|
||||
if absFloat64(stage.stageT-requestedT) < absFloat64(selected.stageT-requestedT) {
|
||||
selected = stage
|
||||
}
|
||||
}
|
||||
|
||||
result := &FieldMapResponse{
|
||||
RequestedT: requestedT,
|
||||
StageT: selected.stageT,
|
||||
Fields: make(map[string][][]float64, 4),
|
||||
}
|
||||
|
||||
for _, fieldName := range []string{"psi", "phi", "T", "C"} {
|
||||
dims, values, err := readDatasetMatrix(filePath, selected.path, fieldName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(dims) != 2 {
|
||||
return nil, fmt.Errorf("unexpected dims for %s: %v", fieldName, dims)
|
||||
}
|
||||
|
||||
matrix, err := reshapeFloat64(values, dims[0], dims[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to reshape dataset %s: %w", fieldName, err)
|
||||
}
|
||||
matrix = transposeFloat64(matrix)
|
||||
if result.Rows == 0 && result.Cols == 0 {
|
||||
result.Rows = len(matrix)
|
||||
if result.Rows > 0 {
|
||||
result.Cols = len(matrix[0])
|
||||
}
|
||||
}
|
||||
result.Fields[fieldName] = matrix
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type stageFieldMap struct {
|
||||
path string
|
||||
stageT float64
|
||||
}
|
||||
|
||||
func listStageGroups(filePath string) ([]stageFieldMap, error) {
|
||||
out, err := runH5Dump(filePath, "-n")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var stages []stageFieldMap
|
||||
for _, line := range strings.Split(string(out), "\n") {
|
||||
matches := stagePathRe.FindStringSubmatch(line)
|
||||
if len(matches) != 2 {
|
||||
continue
|
||||
}
|
||||
stageT, err := strconv.ParseFloat(strings.TrimPrefix(matches[1], "stage_t="), 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
stages = append(stages, stageFieldMap{
|
||||
path: "/map/" + matches[1],
|
||||
stageT: stageT,
|
||||
})
|
||||
}
|
||||
|
||||
return stages, nil
|
||||
}
|
||||
|
||||
func readDatasetMatrix(filePath, stagePath, fieldName string) ([]int, []float64, error) {
|
||||
datasetPath := stagePath + "/" + fieldName
|
||||
|
||||
headerOut, err := runH5Dump(filePath, "-H", "-d", datasetPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rows, cols, err := parseDimsFromHeader(headerOut)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse dims for %s: %w", datasetPath, err)
|
||||
}
|
||||
|
||||
dataOut, err := runH5Dump(filePath, "-d", datasetPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
values, err := parseFloatData(dataOut)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse data for %s: %w", datasetPath, err)
|
||||
}
|
||||
|
||||
if rows*cols != len(values) {
|
||||
return nil, nil, fmt.Errorf("value count %d does not match %dx%d for %s", len(values), rows, cols, datasetPath)
|
||||
}
|
||||
|
||||
return []int{rows, cols}, values, nil
|
||||
}
|
||||
|
||||
func parseDimsFromHeader(out []byte) (int, int, error) {
|
||||
matches := dimsRe.FindSubmatch(out)
|
||||
if len(matches) != 3 {
|
||||
return 0, 0, fmt.Errorf("dimensions not found")
|
||||
}
|
||||
|
||||
rows, err := strconv.Atoi(string(matches[1]))
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
cols, err := strconv.Atoi(string(matches[2]))
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return rows, cols, nil
|
||||
}
|
||||
|
||||
func parseFloatData(out []byte) ([]float64, error) {
|
||||
lines := strings.Split(string(out), "\n")
|
||||
values := make([]float64, 0, 2048)
|
||||
inData := false
|
||||
|
||||
for _, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
switch {
|
||||
case trimmed == "DATA {":
|
||||
inData = true
|
||||
continue
|
||||
case inData && trimmed == "}":
|
||||
return values, nil
|
||||
case !inData:
|
||||
continue
|
||||
}
|
||||
|
||||
colon := strings.Index(trimmed, ":")
|
||||
if colon < 0 {
|
||||
continue
|
||||
}
|
||||
payload := strings.TrimSpace(trimmed[colon+1:])
|
||||
if payload == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
matches := floatInDataRe.FindAllString(payload, -1)
|
||||
for _, match := range matches {
|
||||
value, err := strconv.ParseFloat(match, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values = append(values, value)
|
||||
}
|
||||
}
|
||||
|
||||
if !inData {
|
||||
return nil, fmt.Errorf("data block not found")
|
||||
}
|
||||
return nil, fmt.Errorf("data block not terminated")
|
||||
}
|
||||
|
||||
func reshapeFloat64(values []float64, rows, cols int) ([][]float64, error) {
|
||||
if rows*cols != len(values) {
|
||||
return nil, fmt.Errorf("value count %d does not match %dx%d", len(values), rows, cols)
|
||||
}
|
||||
|
||||
matrix := make([][]float64, rows)
|
||||
for r := 0; r < rows; r++ {
|
||||
start := r * cols
|
||||
row := make([]float64, cols)
|
||||
copy(row, values[start:start+cols])
|
||||
matrix[r] = row
|
||||
}
|
||||
return matrix, nil
|
||||
}
|
||||
|
||||
func transposeFloat64(matrix [][]float64) [][]float64 {
|
||||
if len(matrix) == 0 || len(matrix[0]) == 0 {
|
||||
return matrix
|
||||
}
|
||||
|
||||
rows := len(matrix)
|
||||
cols := len(matrix[0])
|
||||
transposed := make([][]float64, cols)
|
||||
for c := 0; c < cols; c++ {
|
||||
transposed[c] = make([]float64, rows)
|
||||
for r := 0; r < rows; r++ {
|
||||
transposed[c][r] = matrix[r][c]
|
||||
}
|
||||
}
|
||||
return transposed
|
||||
}
|
||||
|
||||
func runH5Dump(filePath string, args ...string) ([]byte, error) {
|
||||
cmdArgs := append(args, filePath)
|
||||
cmd := exec.Command("h5dump", cmdArgs...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("h5dump %v failed: %w: %s", cmdArgs, err, strings.TrimSpace(string(out)))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func absFloat64(value float64) float64 {
|
||||
if value < 0 {
|
||||
return -value
|
||||
}
|
||||
return value
|
||||
}
|
||||
+32
-25
@@ -3,10 +3,10 @@ package control_case
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/otiai10/copy"
|
||||
@@ -22,16 +22,19 @@ type ControlCase struct {
|
||||
}
|
||||
|
||||
type Params struct {
|
||||
gorm.Model
|
||||
ID uint `toml:"-" csv:"id"`
|
||||
Rel float64 `toml:"rel" csv:"rel"`
|
||||
RelC float64 `toml:"rel_c" csv:"rel_c"`
|
||||
Le float64 `toml:"le" csv:"le"`
|
||||
Pr float64 `toml:"pr" csv:"pr"`
|
||||
Pe float64 `toml:"pe" csv:"pe"`
|
||||
InitialCondition string `toml:"-" csv:"initial_condition"`
|
||||
Time float64 `toml:"time" csv:"time"`
|
||||
FolderPath string `toml:"-" csv:"-"`
|
||||
ID uint `gorm:"primaryKey" json:"id" toml:"-" csv:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
|
||||
Rel float64 `json:"rel" toml:"rel" csv:"rel"`
|
||||
RelC float64 `json:"rel_c" toml:"rel_c" csv:"rel_c"`
|
||||
Le float64 `json:"le" toml:"le" csv:"le"`
|
||||
Pr float64 `json:"pr" toml:"pr" csv:"pr"`
|
||||
Pe float64 `json:"pe" toml:"pe" csv:"pe"`
|
||||
Ma float64 `json:"ma" toml:"ma" csv:"ma"`
|
||||
InitialCondition string `json:"initial_condition" toml:"-" csv:"initial_condition"`
|
||||
Time float64 `json:"time" toml:"time" csv:"time"`
|
||||
FolderPath string `json:"folder_path" toml:"-" csv:"-"`
|
||||
}
|
||||
|
||||
func (p *Params) ToTOML(filename string) error {
|
||||
@@ -45,37 +48,40 @@ func (p *Params) ToTOML(filename string) error {
|
||||
return encoder.Encode(p)
|
||||
}
|
||||
|
||||
func (u *Params) AfterCreate(tx *gorm.DB) (err error) {
|
||||
control_case := ControlCase{ParamsID: u.ID, Status: "N"}
|
||||
tx.Create(&control_case)
|
||||
return
|
||||
}
|
||||
func (p *Params) Exist() (bool, error) {
|
||||
folderPath := filepath.Join("./", fmt.Sprintf("%d", p.ID))
|
||||
return exists(folderPath)
|
||||
}
|
||||
func (p *Params) CreateFolder() {
|
||||
func (p *Params) CreateFolder() error {
|
||||
BIN_PATH := "./bio-convect"
|
||||
folderPath := filepath.Join("./", fmt.Sprintf("%d", p.ID))
|
||||
os.MkdirAll(folderPath, os.ModePerm)
|
||||
if err := os.MkdirAll(folderPath, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("folder: %s\n", folderPath)
|
||||
execPath := filepath.Join("./", folderPath, BIN_PATH)
|
||||
err := copy.Copy(BIN_PATH, execPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
if p.InitialCondition != "E" {
|
||||
startPath := filepath.Join("./", folderPath, "storag.h5")
|
||||
if err := os.Chmod(execPath, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
if p.InitialCondition != "" && p.InitialCondition != "E" {
|
||||
startPath := filepath.Join("./", folderPath, "storage.h5")
|
||||
err = copy.Copy(p.InitialCondition, startPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
p.ToTOML(filepath.Join(folderPath, "config.toml"))
|
||||
if err := p.ToTOML(filepath.Join(folderPath, "config.toml")); err != nil {
|
||||
return err
|
||||
}
|
||||
p.FolderPath = folderPath
|
||||
return nil
|
||||
|
||||
}
|
||||
func (p *Params) Run(ctx context.Context) {
|
||||
func (p *Params) Run(ctx context.Context) error {
|
||||
BIN_PATH := "./bio-convect"
|
||||
cmd := exec.CommandContext(ctx, BIN_PATH)
|
||||
cmd.Dir = p.FolderPath
|
||||
@@ -86,7 +92,8 @@ func (p *Params) Run(ctx context.Context) {
|
||||
err := cmd.Run()
|
||||
fmt.Printf("afrer run")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ func RegisterApp(r *gin.Engine, db *gorm.DB) {
|
||||
params := NewParamsController(db)
|
||||
go4rest.RegisterCRUDRoutes(r, "control_case", controller)
|
||||
go4rest.RegisterCRUDRoutes(r, "params", params)
|
||||
r.POST("/api/control_case/launch", controller.Launch)
|
||||
r.POST("/api/control_case/:id/recalculate-analysis", controller.RecalculateAnalysis)
|
||||
r.GET("/api/control_case/:id/chart-data", controller.ChartData)
|
||||
r.GET("/api/control_case/:id/field-map", controller.FieldMap)
|
||||
numJobs := 1
|
||||
//jobs := make(chan Params, numJobs)
|
||||
results := make(chan int, numJobs)
|
||||
|
||||
+41
-17
@@ -5,11 +5,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"control/analize"
|
||||
"github.com/gocarina/gocsv"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -25,11 +26,40 @@ func exists(path string) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
func worker(id int, jobs <-chan Params, ctx context.Context) {
|
||||
func worker(id int, jobs <-chan ControlCase, ctx context.Context, db *gorm.DB) {
|
||||
for j := range jobs {
|
||||
fmt.Printf("Worker %d started job %d \n", id, j.ID)
|
||||
j.CreateFolder()
|
||||
j.Run(ctx)
|
||||
p := j.Params
|
||||
p.FolderPath = filepath.Join(".", fmt.Sprintf("%d", p.ID))
|
||||
|
||||
exists, err := p.Exist()
|
||||
if err != nil {
|
||||
fmt.Printf("Worker %d failed to check folder for job %d: %v\n", id, j.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !exists {
|
||||
if err := p.CreateFolder(); err != nil {
|
||||
fmt.Printf("Worker %d failed to prepare job %d: %v\n", id, j.ID, err)
|
||||
continue
|
||||
}
|
||||
if err := p.Run(ctx); err != nil {
|
||||
fmt.Printf("Worker %d failed to run job %d: %v\n", id, j.ID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
csvPath := filepath.Join(p.FolderPath, "foo.csv")
|
||||
if _, err := analize.AnalyzeCSV(db, j.ID, j.Name, csvPath); err != nil {
|
||||
fmt.Printf("Worker %d failed to analyze job %d: %v\n", id, j.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
j.Status = "R"
|
||||
if err := db.Model(&ControlCase{}).Where("id = ?", j.ID).Update("status", j.Status).Error; err != nil {
|
||||
fmt.Printf("Worker %d failed to update status for job %d: %v\n", id, j.ID, err)
|
||||
continue
|
||||
}
|
||||
time.Sleep(time.Second) // Имитация длительной задачи
|
||||
fmt.Printf("Worker %d finished job %d \n", id, j.ID)
|
||||
// results <- j * 2
|
||||
@@ -39,13 +69,15 @@ func worker(id int, jobs <-chan Params, ctx context.Context) {
|
||||
func readCSVWithGocsv() []Params {
|
||||
file, err := os.Open("db.csv")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
fmt.Printf("failed to open csv: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var params []Params
|
||||
if err := gocsv.UnmarshalFile(file, ¶ms); err != nil {
|
||||
log.Fatal(err)
|
||||
fmt.Printf("failed to parse csv: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, person := range params {
|
||||
@@ -73,7 +105,7 @@ func RunControllWorker(db *gorm.DB, results chan int) {
|
||||
cancel()
|
||||
}() // Cancel if main exits early
|
||||
|
||||
jobs := make(chan Params, numJobs)
|
||||
jobs := make(chan ControlCase, numJobs)
|
||||
//results := make(chan int, numJobs)
|
||||
|
||||
// Запуск воркеров
|
||||
@@ -82,7 +114,7 @@ func RunControllWorker(db *gorm.DB, results chan int) {
|
||||
wg.Add(1)
|
||||
go func(w int) {
|
||||
defer wg.Done()
|
||||
worker(w, jobs, ctx)
|
||||
worker(w, jobs, ctx, db)
|
||||
}(w)
|
||||
}
|
||||
|
||||
@@ -91,15 +123,7 @@ func RunControllWorker(db *gorm.DB, results chan int) {
|
||||
cases := readFromDb(db)
|
||||
// Отправка задач
|
||||
for _, c := range cases {
|
||||
p := c.Params
|
||||
e, _ := p.Exist()
|
||||
if e {
|
||||
c.Status = "R"
|
||||
db.Save((&c))
|
||||
} else {
|
||||
p.CreateFolder()
|
||||
jobs <- p
|
||||
}
|
||||
jobs <- c
|
||||
}
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user