Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Aplica-se a: SQL Server
SSIS Integration Runtime em Azure Data Factory
O motor de tempo de execução dos Serviços de Integração permite que pacotes, tarefas e outros tipos de contentores sejam suspensos durante a execução, utilizando pontos de interrupção. A utilização de pontos de interrupção permite-lhe rever e corrigir erros que impedem a sua aplicação ou tarefas de correrem corretamente. A arquitetura de ponto de interrupção permite ao cliente avaliar o valor em tempo de execução dos objetos do pacote em pontos definidos de execução enquanto o processamento da tarefa está suspenso.
Os programadores de tarefas personalizadas podem usar esta arquitetura para criar alvos de breakpoint personalizados, utilizando a IDTSBreakpointSite interface e a sua interface principal, IDTSSuspend. A IDTSBreakpointSite interface define a interação entre o motor de execução e a tarefa de criar e gerir locais ou alvos personalizados de pontos de interrupção. A IDTSSuspend interface fornece métodos e propriedades que são chamados pelo motor de execução para notificar a tarefa para suspender ou retomar a sua execução.
Um local ou alvo de ponto de interrupção é um ponto na execução da tarefa onde o processamento pode ser suspenso. Os utilizadores selecionam entre os locais disponíveis de pontos de interrupção na caixa de diálogo Definir pontos de interrupção . Por exemplo, além das opções de ponto de interrupção padrão, o Foreach Loop Container oferece a opção "Interromper no início de cada iteração do ciclo".
Quando uma tarefa atinge um alvo de ponto de interrupção durante a execução, avalia-o para determinar se este ponto de interrupção está ativado. Isto indica que o utilizador quer que a execução pare nesse ponto de interrupção. Se o ponto de interrupção estiver ativado, a tarefa eleva o OnBreakpointHit evento para o motor de execução. O motor de execução responde ao evento chamando o método Suspend de cada tarefa que está atualmente a correr no pacote. A execução da tarefa recomeça quando o runtime chama o método ResumeExecution da tarefa suspensa.
As tarefas que não utilizam pontos de interrupção devem ainda assim implementar as IDTSBreakpointSite interfaces and IDTSSuspend . Isto garante que a tarefa é suspensa corretamente quando outros objetos do pacote geram OnBreakpointHit eventos.
Interface IDTSBreakpointSite e Breakpoint Manager
As tarefas criam alvos de breakpoint ao chamar o CreateBreakpointTarget método do BreakpointManager, fornecendo um ID inteiro e uma descrição de string como parâmetros. Quando a tarefa atinge o ponto no seu código que contém um alvo de ponto de interrupção, ela avalia o alvo do ponto de interrupção usando o IsBreakpointTargetEnabled método para determinar se esse ponto de interrupção está ativado. Se for verdade, a tarefa notifica o motor de tempo de execução ao elevar o OnBreakpointHit evento.
A IDTSBreakpointSite interface define um único método, AcceptBreakpointManager, que é chamado pelo motor de execução durante a criação da tarefa. Este método fornece como parâmetro o BreakpointManager objeto, que é então usado pela tarefa para criar e gerir os seus pontos de interrupção. As tarefas devem armazenar localmente BreakpointManager para uso durante os métodos Validar e Executar .
O seguinte código de exemplo demonstra como criar um alvo de ponto de interrupção usando o BreakpointManager. A amostra chama o OnBreakpointHit método para elevar o evento.
public void AcceptBreakpointManager( BreakpointManager breakPointManager )
{
// Store the breakpoint manager locally.
this.bpm = breakPointManager;
}
public override DTSExecResult Execute( Connections connections,
Variables variables, IDTSComponentEvents events,
IDTSLogging log, DtsTransaction txn)
{
// Create a breakpoint.
this.bpm.CreateBreakPointTarget( 1 , "A sample breakpoint target." );
...
if( this.bpm.IsBreakpointTargetEnabled( 1 ) == true )
events.OnBreakpointHit( this.bpm.GetBreakpointTarget( 1 ) );
}
Public Sub AcceptBreakpointManager(ByVal breakPointManager As BreakpointManager)
' Store the breakpoint manager locally.
Me.bpm = breakPointManager
End Sub
Public Overrides Function Execute(ByVal connections As Connections, _
ByVal variables As Variables, ByVal events As IDTSComponentEvents, _
ByVal log As IDTSLogging, ByVal txn As DtsTransaction) As DTSExecResult
' Create a breakpoint.
Me.bpm.CreateBreakPointTarget(1 , "A sample breakpoint target.")
If Me.bpm.IsBreakpointTargetEnabled(1) = True Then
events.OnBreakpointHit(Me.bpm.GetBreakpointTarget(1))
End If
End Function
IDTSSuspend Interface
A IDTSSuspend interface define os métodos que são chamados pelo motor de execução quando este pausa ou retoma a execução de uma tarefa. A IDTSSuspend interface é implementada pela IDTSBreakpointSite interface, e os seus métodos Suspend e ResumeExecution são geralmente sobrepostos pela tarefa personalizada. Quando o motor de execução recebe um evento OnBreakpointHit de uma tarefa, chama o método Suspend de cada tarefa em execução, notificando as tarefas para pausarem. Quando o cliente retoma a execução, o motor de execução chama o método ResumeExecution das tarefas suspensas.
Suspender e retomar a execução da tarefa envolve pausar e retomar o fio de execução da tarefa. No código gerido, faz-se isto usando a classe ManualResetEvent no espaço de nomes System.Threading do framework .NET.
O exemplo de código seguinte demonstra a suspensão e retoma da execução de tarefas. Note que o método Execute mudou em relação ao exemplo de código anterior, e o thread de execução fica pausado ao disparar o ponto de interrupção.
private ManualResetEvent m_suspended = new ManualResetEvent( true );
private ManualResetEvent m_canExecute = new ManualResetEvent( true );
private int m_suspendRequired = 0;
private int m_debugMode = 0;
public override DTSExecResult Execute( Connections connections, Variables variables, IDTSComponentEvents events, IDTSLogging log, DtsTransaction txn)
{
// While a task is not executing, it is suspended.
// Now that we are executing,
// change to not suspended.
ChangeEvent(m_suspended, false);
// Check for a suspend before doing any work,
// in case the suspend and execute calls
// were initiated at virtually the same time.
CheckAndSuspend();
CheckAndFireBreakpoint( componentEvents, 1);
}
private void CheckAndSuspend()
{
// Loop until we can execute.
// The loop is required rather than a simple If
// because there is a time between the return from WaitOne and the
// reset that we might receive another Suspend call.
// Suspend() will see that we are suspended
// and return. So we need to rewait.
while (!m_canExecute.WaitOne(0, false))
{
ChangeEvent(m_suspended, true);
m_canExecute.WaitOne();
ChangeEvent(m_suspended, false);
}
}
private void CheckAndFireBreakpoint(IDTSComponentEvents events, int breakpointID)
{
// If the breakpoint is enabled, fire it.
if (m_debugMode != 0 && this.bpm.IsBreakpointTargetEnabled(breakpointID))
{
// Enter a suspend mode before firing the breakpoint.
// Firing the breakpoint will cause the runtime
// to call Suspend on this task.
// Because we are blocked on the breakpoint,
// we are suspended.
ChangeEvent(m_suspended, true);
events.OnBreakpointHit(this.bpm.GetBreakpointTarget(breakpointID));
ChangeEvent(m_suspended, false);
}
// Check for a suspension for two reasons:
// 1. If we are at a point where we could fire a breakpoint,
// we are at a valid suspend point. Even if we didn't hit a
// breakpoint, the runtime may have called suspend,
// so check for it.
// 2. Between the return from OnBreakpointHit
// and the reset of the event, it is possible to have
// received a suspend call from which we returned because
// we were already suspended. We need to be sure it is okay
// to continue executing now.
CheckAndSuspend();
}
static void ChangeEvent(ManualResetEvent e, bool shouldSet)
{
bool succeeded;
if (shouldSet)
succeeded = e.Set();
else
succeeded = e.Reset();
if (!succeeded)
throw new Exception("Synchronization object failed.");
}
public bool SuspendRequired
{
get {return m_suspendRequired != 0;}
set
{
// This lock is also taken by Suspend().
// Because it is possible for the package to be
// suspended and resumed in quick succession,
// this property might be set before
// the actual Suspend() call.
// Without the lock, the Suspend() might reset the canExecute
// event after we set it to abort the suspension.
lock (this)
{
Interlocked.Exchange(ref m_suspendRequired, value ? 1 : 0);
if (!value)
ResumeExecution();
}
}
}
public void ResumeExecution()
{
ChangeEvent( m_canExecute,true );
}
public void Suspend()
{
// This lock is also taken by the set SuspendRequired method.
// It prevents this call from overriding an
// aborted suspension. See comments in set SuspendRequired.
lock (this)
{
// If a Suspend is required, do it.
if (m_suspendRequired != 0)
ChangeEvent(m_canExecute, false);
}
// We can't return from Suspend until the task is "suspended".
// This can happen one of two ways:
// the m_suspended event occurs, indicating that the execute thread
// has suspended, or the canExecute flag is set,
// indicating that a suspend is no longer required.
WaitHandle [] suspendOperationComplete = {m_suspended, m_canExecute};
WaitHandle.WaitAny(suspendOperationComplete);
}
Private m_suspended As ManualResetEvent = New ManualResetEvent(True)
Private m_canExecute As ManualResetEvent = New ManualResetEvent(True)
Private m_suspendRequired As Integer = 0
Private m_debugMode As Integer = 0
Public Overrides Function Execute(ByVal connections As Connections, _
ByVal variables As Variables, ByVal events As IDTSComponentEvents, _
ByVal log As IDTSLogging, ByVal txn As DtsTransaction) As DTSExecResult
' While a task is not executing it is suspended.
' Now that we are executing,
' change to not suspended.
ChangeEvent(m_suspended, False)
' Check for a suspend before doing any work,
' in case the suspend and execute calls
' were initiated at virtually the same time.
CheckAndSuspend()
CheckAndFireBreakpoint(componentEvents, 1)
End Function
Private Sub CheckAndSuspend()
' Loop until we can execute.
' The loop is required rather than a simple if
' because there is a time between the return from WaitOne and the
' reset that we might receive another Suspend call.
' Suspend() will see that we are suspended
' and return. So we need to rewait.
Do While Not m_canExecute.WaitOne(0, False)
ChangeEvent(m_suspended, True)
m_canExecute.WaitOne()
ChangeEvent(m_suspended, False)
Loop
End Sub
Private Sub CheckAndFireBreakpoint(ByVal events As IDTSComponentEvents, _
ByVal breakpointID As Integer)
' If the breakpoint is enabled, fire it.
If m_debugMode <> 0 AndAlso Me.bpm.IsBreakpointTargetEnabled(breakpointID) Then
' Enter a suspend mode before firing the breakpoint.
' Firing the breakpoint will cause the runtime
' to call Suspend on this task.
' Because we are blocked on the breakpoint,
' we are suspended.
ChangeEvent(m_suspended, True)
events.OnBreakpointHit(Me.bpm.GetBreakpointTarget(breakpointID))
ChangeEvent(m_suspended, False)
End If
' Check for a suspension for two reasons:
' 1. If we are at a point where we could fire a breakpoint,
' we are at a valid suspend point. Even if we didn't hit a
' breakpoint, the runtime may have called suspend,
' so check for it.
' 2. Between the return from OnBreakpointHit
' and the reset of the event, it is possible to have
' received a suspend call from which we returned because
' we were already suspended. We need to be sure it is okay
' to continue executing now.
CheckAndSuspend()
End Sub
Shared Sub ChangeEvent(ByVal e As ManualResetEvent, ByVal shouldSet As Boolean)
Dim succeeded As Boolean
If shouldSet Then
succeeded = e.Set()
Else
succeeded = e.Reset()
End If
If (Not succeeded) Then
Throw New Exception("Synchronization object failed.")
End If
End Sub
Public Property SuspendRequired() As Boolean
Get
Return m_suspendRequired <> 0
End Get
Set
' This lock is also taken by Suspend().
' Because it is possible for the package to be
' suspended and resumed in quick succession,
' this property might be set before
' the actual Suspend() call.
' Without the lock, the Suspend() might reset the canExecute
' event after we set it to abort the suspension.
SyncLock Me
Interlocked.Exchange(m_suspendRequired,IIf(Value, 1, 0))
If (Not Value) Then
ResumeExecution()
End If
End SyncLock
End Set
End Property
Public Sub ResumeExecution()
ChangeEvent(m_canExecute,True)
End Sub
Public Sub Suspend()
' This lock is also taken by the set SuspendRequired method.
' It prevents this call from overriding an
' aborted suspension. See comments in set SuspendRequired.
SyncLock Me
' If a Suspend is required, do it.
If m_suspendRequired <> 0 Then
ChangeEvent(m_canExecute, False)
End If
End SyncLock
' We can't return from Suspend until the task is "suspended".
' This can happen one of two ways:
' the m_suspended event occurs, indicating that the execute thread
' has suspended, or the canExecute flag is set,
' indicating that a suspend is no longer required.
Dim suspendOperationComplete As WaitHandle() = {m_suspended, m_canExecute}
WaitHandle.WaitAny(suspendOperationComplete)
End Sub