// Spool spools code of an app from Cocaine Storage service func (b *Box) Spool(ctx context.Context, name string, opts isolate.Profile) (err error) { spoolPath := b.spoolPath if val, ok := opts["spool"]; ok { spoolPath = fmt.Sprintf("%s", val) } defer apexctx.GetLogger(ctx).WithField("name", name).WithField("spoolpath", spoolPath).Trace("processBox.Spool").Stop(&err) data, err := b.fetch(ctx, name) if err != nil { return err } if isolate.IsCancelled(ctx) { return nil } return unpackArchive(ctx, data, filepath.Join(spoolPath, name)) }
// Spawn spawns a new process func (b *Box) Spawn(ctx context.Context, config isolate.SpawnConfig, output io.Writer) (proc isolate.Process, err error) { spoolPath := b.spoolPath if val, ok := config.Opts["spool"]; ok { spoolPath = fmt.Sprintf("%s", val) } workDir := filepath.Join(spoolPath, config.Name) var execPath = config.Executable if !filepath.IsAbs(config.Executable) { execPath = filepath.Join(workDir, config.Executable) } packedEnv := make([]string, 0, len(config.Env)) for k, v := range config.Env { packedEnv = append(packedEnv, k+"="+v) } packedArgs := make([]string, 1, len(config.Args)*2+1) packedArgs[0] = filepath.Base(config.Executable) for k, v := range config.Args { packedArgs = append(packedArgs, k, v) } defer apexctx.GetLogger(ctx).WithFields( log.Fields{"name": config.Name, "executable": config.Executable, "workDir": workDir, "execPath": execPath}).Trace("processBox.Spawn").Stop(&err) // Update statistics start := time.Now() spawningQueueSize.Inc(1) if spawningQueueSize.Count() > 10 { spawningQueueSize.Dec(1) return nil, syscall.EAGAIN } err = b.spawnSm.Acquire(ctx) spawningQueueSize.Dec(1) if err != nil { return nil, isolate.ErrSpawningCancelled } defer b.spawnSm.Release() // NOTE: once process was put to the map // its waiter responsibility to Wait for it. // NOTE: No defer here b.mu.Lock() if isolate.IsCancelled(ctx) { b.mu.Unlock() return nil, isolate.ErrSpawningCancelled } newProcStart := time.Now() pr, err := newProcess(ctx, execPath, packedArgs, packedEnv, workDir, output) newProcStarted := time.Now() // Update has lock, so move it out from Hot spot defer procsNewTimer.Update(newProcStarted.Sub(newProcStart)) if err != nil { b.mu.Unlock() procsErroredCounter.Inc(1) return nil, err } b.children[pr.cmd.Process.Pid] = pr.cmd b.mu.Unlock() totalSpawnTimer.UpdateSince(start) isolate.NotifyAboutStart(output) procsCreatedCounter.Inc(1) return pr, err }