2012-02-16 16 views
5

¿Es posible cola de compilaciones sincrónicamente?TFS 2010 API: la cola se crea de forma síncrona y obtiene el estado de cada compilación en cola: "Ejecutar en el agente (esperando el agente de compilación)"

que hemos probado algo como esto:

CodeActivity:

[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 
     }; 
    } 
} 

BuildResult:

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; 
      } 
     } 
    } 
} 

Así que estoy tratando de esperar mientras se completa o cancela la compilación, pero esto no funciona, porque el agente de compilación de la compilación secundaria está esperando todo el tiempo.

Tengo un proceso de compilación principal (se ejecuta en el agente 1) que invoca 13 procesos de subcompilación (todos ejecutados en el agente 2). Y quiero esperar cada proceso de subcompilación para poder abortar el proceso de compilación maestra cuando falla un proceso de subcompilación.

¿Alguna idea?

ACTUALIZACIÓN:

servicio 'XXX - agente1' tenía una excepción: Mensaje de excepción: La operación no se ha completado dentro del tiempo de espera asignado de 00:00:30. El tiempo asignado a esta operación puede haber sido una parte de un tiempo de espera más largo de . (Tipo FaultException`1)

Excepción Seguimiento de la pila: en Microsoft.TeamFoundation.Build.Machine.BuildAgentService.TerminateWorkflow (TerminatingException ex)

El flujo de trabajo:

enter image description here

+1

¿Estás diciendo que no se puede iniciar TODA tu compilación solicitada mediante programación? ¿O que no puedes ordenar múltiples Builds? – pantelif

+1

Se cuelga en la primera subconstrucción en cola. "Ejecutar en agente (esperando el agente de compilación). El agente de compilación para la compilación secundaria tiene el estado:" Ejecutar flujo de trabajo ". El estado del agente de compilación para la compilación principal es:" Listo " – Rookian

+1

Me di cuenta de que el agente no cuelgue cada vez. El agente de compilación se "cuelga" esporádicamente. – Rookian

Respuesta

1

Como todo lo que tiene es un Agente de compilación adicional, creo que no le aporta mucho para emplear un módulo tan complejo.

Implementaría dos actividades separadas:
Una actividad que toma como entrada un BuildDetail y un BuildDefinition como salidas una vez que se ha puesto en cola una nueva compilación.
Invocaría esta actividad dentro de un bucle en el XAML. Esto pondría en cola todas las compilaciones en el agente de compilación n.º 2.

La segunda actividad verificaría el estado del agente de compilación # 2 & espere a que el agente vuelva a estar inactivo.
Una vez que lo haga, buscaría cada definición de compilación que se haya ejecutado correctamente en el Agente # 2 con algo como eso:
if(buildDefinition.LastGoodBuildUri != buildDefinition.LastBuildUri)

Lo que podría parecer una desventaja con este enfoque, es que la construcción NO fallará/detenerse en las primeras compilaciones de "niño" que se rompen.
En mi opinión, eso es realmente una ventaja: si más de uno falla, lo sabrá de inmediato.

+0

Sí encontré el problema. El agente de compilación incorrecto es elegido por la compilación de mi maestro. Pero no sé por qué este es el caso, porque configuré la definición de compilación maestra para usar un agente específico. – Rookian

1

Creé una plantilla especial para iniciar compilaciones en orden. La plantilla básica:

Obtener la construcción, QueueBuild, MonitorBuild

Obtener el Build es la actividad que está en la plantilla por defecto. Es la primera actividad en mi plantilla y solo se llama una vez al principio.

QueueBuild es la actividad obtenida de TFSExtensions en codeplex. Creo una variable que contiene un objeto IQueueBuild que es el resultado de la actividad QueueBuild para cada compilación que planeo iniciar. Establecí el resultado en esta variable. Llamé a la mía CurrentQueueBuild. Después de que cada actividad de QueueBuild inicie una compilación, la actividad actualiza esta variable a la cola de compilación actual.

MonitorBuild es una secuencia que hice que hace la mayor parte de la 'sincronización':

En primer lugar es una actividad que comprueba si CurrentQueueBuild es nulo (CurrentQueueBuild es nada). Si es así, arrojo una excepción ya que no puedo tener eso.

La segunda es una actividad While (llamada 'While building'). Su condición es 'CurrentQueueBuild.Status = BuildStatus.InProgress'. En el cuerpo de the the while tengo otra secuencia que contiene una actividad InvokeMethod (TargetObject = CurrentQueueBuild, MethodName = Refresh y agregué en el parámetro de tipo QueryOptions establecido en QueryOptions.All). Sigo el InvokeMethod con una actividad de demora configurada para esperar 5 segundos.

Finalmente escribo un mensaje de compilación para registrar el estado. Esto obviamente es opcional.

Así que para concluir, tengo 5 construye pateo fuera y por cada uno me tener una actividad QueueBuild seguido de un monitor Construir actividad juntos como se describe anteriormente.

Espero que esto ayude a alguien.

+1

¿Cómo esta NO es la respuesta aceptada? Esta fue una solución muy simple para lo que podría ser un problema desagradable. – JohnZaj

Cuestiones relacionadas