func (attempt *attempt) Finish(data map[string]interface{}) error { globalLock(attempt) defer globalUnlock(attempt) if attempt.status != coordinate.Failed && !attempt.isPending() { return coordinate.ErrNotPending } attempt.finish(coordinate.Finished, data) // Does the work unit data include an "output" key that we // understand? if attempt.workUnit.activeAttempt != attempt { return nil } if data == nil { data = attempt.data } if data == nil { data = attempt.workUnit.data } var newUnits map[string]coordinate.AddWorkUnitItem var nextWorkSpec *workSpec output, ok := data["output"] if ok { newUnits = coordinate.ExtractWorkUnitOutput(output) } if newUnits != nil { then := attempt.workUnit.workSpec.meta.NextWorkSpecName if then != "" { nextWorkSpec, ok = attempt.workUnit.workSpec.namespace.workSpecs[then] nextWorkSpec.addWorkUnits(newUnits) } } return nil }
func (a *attempt) Finish(data map[string]interface{}) error { return withTx(a, func(tx *sql.Tx) error { err := a.complete(tx, data, "finished") if err != nil { return err } // Does the work unit data include an "output" key // that we understand? We may need to ring back to // the work unit here; we need the next work spec name // too in any case outputs := []string{workSpecNextWorkSpec, workUnitAttempt} tables := []string{workSpecTable, workUnitTable} conditions := []string{isWorkUnit, workUnitInSpec} if data == nil { outputs = append(outputs, workUnitData, attemptData) tables = append(tables, attemptTable) conditions = append(conditions, attemptThisWorkUnit) } query := buildSelect(outputs, tables, conditions) row := tx.QueryRow(query, a.unit.id) var attemptID sql.NullInt64 var nextWorkSpec string if data == nil { var unitData, attemptData []byte err = row.Scan(&nextWorkSpec, &attemptID, &unitData, &attemptData) if err == nil { if attemptData != nil { data, err = bytesToMap(attemptData) } else if unitData != nil { data, err = bytesToMap(unitData) } else { data = map[string]interface{}{} } } } else { err = row.Scan(&nextWorkSpec, &attemptID) } if err != nil { return err } if nextWorkSpec == "" { return nil // nothing to do } if !attemptID.Valid || (attemptID.Int64 != int64(a.id)) { return nil // no longer active attempt } // TODO(dmaze): This should become a join in the // previous query query = buildSelect([]string{ workSpecID, }, []string{ workSpecTable, }, []string{ inThisNamespace, workSpecName + "=$2", }) row = tx.QueryRow(query, a.unit.spec.namespace.id, nextWorkSpec) var nextWorkSpecID int err = row.Scan(&nextWorkSpecID) if err != nil { return err } units := coordinate.ExtractWorkUnitOutput(data["output"]) if units == nil { return nil // nothing to do } for name, item := range units { var dataBytes []byte dataBytes, err = mapToBytes(item.Data) if err != nil { return err } _, err = tx.Exec("INSERT INTO "+workUnitTable+"(work_spec_id, name, data, priority) VALUES ($1, $2, $3, $4)", nextWorkSpecID, name, dataBytes, item.Priority) if err != nil { return err } } return nil }) }