API TFS 2010: Синхронная сборка очереди и получение состояния каждой сборки в очереди: Запуск на агенте (ожидание агента сборки)

Можно ли ставить сборки в очередь синхронно?

Я пробовал что-то вроде этого:

Кодовая активность:

[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class QueueNewBuild : CodeActivity<BuildResult>
{
    // The Team Project that the build definition belongs to.
    [RequiredArgument]
    public InArgument<IBuildDetail> BuildDetail { get; set; }

    // The build definition to queue
    [RequiredArgument]
    public InArgument<String> BuildDefinition { get; set; }

    protected override BuildResult Execute(CodeActivityContext context)
    {
        // Obtain the runtime value of the input arguments
        var buildDefinitionName = context.GetValue(BuildDefinition);
        var buildDetail = context.GetValue(BuildDetail);

        // Obtain the Team Project for the current build definition.
        var tfsProject = buildDetail.BuildDefinition.TeamProject;

        var configurationServerUri = buildDetail.BuildServer.TeamProjectCollection.Uri.ToString();

        var server = new TfsTeamProjectCollection(new Uri(configurationServerUri));
        server.EnsureAuthenticated();
        var buildServer = server.GetService<IBuildServer>();
        var buildDefinition = buildServer.GetBuildDefinition(tfsProject, buildDefinitionName);

        var queuedBuild = buildServer.QueueBuild(buildDefinition);

        var buildStatusWatcher = new BuildStatusWatcher(queuedBuild.Id);
        buildStatusWatcher.Connect(buildServer, tfsProject);

        do
        {
        } while (buildStatusWatcher.Status != QueueStatus.Completed && buildStatusWatcher.Status != QueueStatus.Canceled);

        buildStatusWatcher.Disconnect();

        return new BuildResult
        {
            WasSuccessfully = buildStatusWatcher.Build.CompilationStatus == BuildPhaseStatus.Succeeded, 
            BuildDetail = buildStatusWatcher.Build
        };
    }
}

Результат сборки:

public class BuildResult
{
    public bool WasSuccessfully { get; set; }
    public IBuildDetail BuildDetail { get; set; }
}

BuildStatusWatcher:

public class BuildStatusWatcher
{
    private IQueuedBuildsView _queuedBuildsView;
    private readonly int _queueBuildId;
    private QueueStatus _status;
    private IBuildDetail _build;

    public BuildStatusWatcher(int queueBuildId)
    {
        _queueBuildId = queueBuildId;
    }

    public IBuildDetail Build
    {
        get { return _build; }
    }

    public QueueStatus Status
    {
        get { return _status; }
    }

    public void Connect(IBuildServer buildServer, string tfsProject)
    {
        _queuedBuildsView = buildServer.CreateQueuedBuildsView(tfsProject);
        _queuedBuildsView.StatusChanged += QueuedBuildsViewStatusChanged;
        _queuedBuildsView.Connect(10000, null);
    }

    public void Disconnect()
    {
        _queuedBuildsView.Disconnect();
    }

    private void QueuedBuildsViewStatusChanged(object sender, StatusChangedEventArgs e)
    {
        if (e.Changed)
        {
            var queuedBuild = _queuedBuildsView.QueuedBuilds.FirstOrDefault(x => x.Id == _queueBuildId);
            if (queuedBuild != null)
            {
                _status = queuedBuild.Status;
                _build = queuedBuild.Build;
            }
        }
    }
}

Поэтому я пытаюсь ждать, пока сборка завершена или отменена, но это не работает, потому что агент сборки подсборки все время ждет.

У меня есть один основной процесс сборки (запускается на агенте 1), который вызывает 13 вспомогательных процессов сборки (все выполняются на агенте 2). И я хочу дождаться каждого процесса вспомогательной сборки, чтобы я мог прервать основной процесс сборки, когда процесс вспомогательной сборки завершается сбоем.

Есть идеи?

ОБНОВЛЕНИЕ:

Служба «XXX — Agent1» имела исключение: Сообщение об исключении: операция не была завершена в течение отведенного тайм-аута 00:00:30. Время, отведенное на эту операцию, могло быть частью более длительного тайм-аута. (введите FaultException`1)

Трассировка стека исключений: в Microsoft.TeamFoundation.Build.Machine.BuildAgentService.TerminateWorkflow (исключение TerminatingException ex)

Рабочий процесс:

введите здесь описание изображения


person Rookian    schedule 16.02.2012    source источник
comment
Итак, вы говорите, что ВСЕ ваши программно запрошенные сборки не запускаются? Или что вы не можете заказать несколько сборок?   -  person pantelif    schedule 16.02.2012
comment
Он зависает на первой подсборке в очереди. Запустить агент (ожидание агента сборки). Агент сборки для подсборки имеет состояние: Выполняется рабочий процесс. Состояние агента сборки для основной сборки: Готов   -  person Rookian    schedule 16.02.2012
comment
Я разобрался, что агент не зависает каждый раз. Агент сборки время от времени зависает.   -  person Rookian    schedule 17.02.2012


Ответы (2)


Поскольку все, что у вас есть, — это один дополнительный Build Agent, я думаю, что использование такого сложного модуля не принесет вам многого.

Я бы реализовал два отдельных действия:
Одно действие, которое принимает в качестве входных данных BuildDetail и BuildDefinition as завершается, как только новая сборка поставлена ​​в очередь.
Я бы вызывал это действие в цикле XAML. Это поставит все сборки в очередь в агенте сборки №2.

Второе действие будет проверять статус агента сборки №2 и ждать, пока агент снова станет бездействующим.
После этого я проверю каждое определение сборки, которое должно быть выполнено успешно. в агенте № 2 с чем-то вроде этого:
if(buildDefinition.LastGoodBuildUri != buildDefinition.LastBuildUri)

Что может показаться недостатком этого подхода, так это тот факт, что сборка НЕ ​​завершится ошибкой/остановится при самой первой ломающейся "дочерней" сборке.
По моему мнению, это на самом деле преимущество: если более одного из них выйдет из строя, вы сразу узнаете об этом.

person pantelif    schedule 16.02.2012
comment
Я нашел проблему. Неправильный агент сборки выбран моей основной сборкой. Но я не знаю, почему это так, потому что я настроил определение основной сборки для использования определенного агента. - person Rookian; 20.02.2012

Я создал специальный шаблон для запуска сборок по порядку. Основной шаблон:

Получить сборку, QueueBuild, MonitorBuild

Получить сборку — это действие в шаблоне по умолчанию. Это первое действие в моем шаблоне, и оно вызывается только один раз в начале.

QueueBuild — это активность, полученная от TFSExtensions в codeplex. Я создаю переменную, содержащую объект IQueueBuild, который является результатом действия QueueBuild для каждой сборки, которую я планирую запустить. Я установил результат в эту переменную. Я назвал свой CurrentQueueBuild. После того, как каждое действие QueueBuild запускает сборку, эта переменная обновляется действием до текущей очереди сборки.

MonitorBuild — это созданная мной последовательность, которая выполняет большую часть «синхронизации»:

Во-первых, это действие, которое проверяет, является ли CurrentQueueBuild значением null (CurrentQueueBuild Is Nothing). Если это так, я выбрасываю исключение, поскольку у меня этого не может быть.

Во-вторых, это действие «Пока» (называемое «Во время строительства»). Его условие: «CurrentQueueBuild.Status = BuildStatus.InProgress». В теле файла While у меня есть другая последовательность, содержащая действие InvokeMethod (TargetObject = CurrentQueueBuild, MethodName = Refresh, и я добавил параметр In типа QueryOptions, для которого задано значение QueryOptions.All). Я следую InvokeMethod с задержкой, установленной на 5 секунд.

Наконец, я пишу сообщение о сборке, чтобы регистрировать статус. Это, очевидно, необязательно.

Итак, в завершение у меня есть 5 сборок, которые я запускаю, и для каждой у меня есть действие QueueBuild, за которым следует действие Monitor Build, объединенное, как описано выше.

Надеюсь, это поможет кому-то.

person Mike Cheel    schedule 26.06.2012
comment
Как это НЕ принятый ответ? Это было очень простое решение того, что может быть неприятной проблемой. - person JohnZaj; 19.06.2014