Skip to content

"probably an cyclic dep or infinite loop" on huge graphs #820

@alex65536

Description

@alex65536

If the graph is large, you may get the following error:

task: maximum task call exceeded (100) for task: probably an cyclic dep or infinite loop

The reasons are as follows:

task/task.go

Lines 110 to 112 in bf9cd76

if !e.Watch && atomic.AddInt32(e.taskCallCount[call.Task], 1) >= MaximumTaskCall {
return &MaximumTaskCallExceededError{task: call.Task}
}

So, if we try to execute the task >= 100 times, then we crash.

The issue is that RunTask is executed once from each of the dependencies:

task/task.go

Lines 200 to 206 in bf9cd76

g.Go(func() error {
err := e.RunTask(ctx, taskfile.Call{Task: d.Task, Vars: d.Vars})
if err != nil {
return err
}
return nil
})

but we increment the counter before checking if the task is already running or finished. Such check is done below, in startExecution:

task/task.go

Lines 300 to 327 in bf9cd76

func (e *Executor) startExecution(ctx context.Context, t *taskfile.Task, execute func(ctx context.Context) error) error {
h, err := e.GetHash(t)
if err != nil {
return err
}
if h == "" {
return execute(ctx)
}
e.executionHashesMutex.Lock()
otherExecutionCtx, ok := e.executionHashes[h]
if ok {
e.executionHashesMutex.Unlock()
e.Logger.VerboseErrf(logger.Magenta, "task: skipping execution of task: %s", h)
<-otherExecutionCtx.Done()
return nil
}
ctx, cancel := context.WithCancel(ctx)
defer cancel()
e.executionHashes[h] = ctx
e.executionHashesMutex.Unlock()
return execute(ctx)
}

So, if there is a task on which 100 other tasks depend, then the graph will fail with an error.

Moreover, if you read startExecution carefully, then it would appear that the error has nothing to do with cyclic deps. The simplified algorithm is as follows:

RunTask(task) {
  if (hashes.contains(task)) {
    // wait for task
    return;
  }
  hashes.insert(task);
  // iterate over deps
  // run commands
}

So, even for cyclic dependency, the task will be executed once (though, it will eventually stuck waiting for itself).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions