Compartilhar via


Estrutura de trabalho do temporizador PnP

A estrutura de trabalho do temporizador PnP é um conjunto de classes projetado para facilitar a criação de processos em segundo plano que operam em relação a sites do SharePoint. A estrutura de trabalho do temporizador é semelhante aos trabalhos de temporizador de código de confiança total local (SPJobDefinition). A principal diferença entre a estrutura de trabalho do temporizador e o trabalho de temporizador de código de confiança total é que a estrutura de trabalho do temporizador usa apenas APIs do lado do cliente e, portanto, pode (e deve) ser executada fora do SharePoint. A estrutura de trabalho do temporizador torna possível criar trabalhos de temporizador que operam no SharePoint Online.

Depois que um trabalho de temporizador for criado, ele precisa ser agendado e executado. As duas opções mais comuns são:

  • Quando o Microsoft Azure é a plataforma de hospedagem, trabalhos de temporizador podem ser implantados e executados como WebJobs do Azure.
  • Quando o Windows Server é a plataforma de hospedagem (por exemplo, para o SharePoint local), trabalhos de temporizador podem ser implantados e executados no Windows Scheduler.

Para obter uma introdução em vídeo a trabalhos de temporizador, confira o vídeo Introdução à estrutura de trabalho do temporizador PnP, que apresenta a estrutura de trabalho do temporizador e demonstra o exemplo de trabalho de temporizador simples.

Exemplo de trabalho de temporizador simples

Nesta seção, você aprenderá a criar um trabalho de temporizador muito simples. O objetivo deste exemplo é fornecer ao leitor uma exibição rápida; posteriormente, fornecemos uma explicação mais detalhada da estrutura de trabalho do temporizador.

Observação

Para obter uma solução PnP mais extensa com dez exemplos de trabalho de temporizador individuais, desde exemplos de "Hello world" até trabalhos reais de expiração de conteúdo, consulte Core.TimerJobs.Samples.

As etapas a seguir descrevem como criar um trabalho de temporizador simples.

Etapa 1: Criar um projeto de console e fazer referência ao PnP Core

Crie um novo projeto do tipo "console" e referencie a biblioteca do PnP Core fazendo um dos seguintes procedimentos:

  • Adicione o pacote NuGet do Office 365 Developer Patterns and Practices Core ao seu projeto. Há um pacote NuGet para v15 (local) e para v16 (Office 365). Essa é a opção preferencial.

  • Adicione o projeto de origem PnP Core existente ao seu projeto. Isso permite que você entre no código principal PnP ao depurar.

    Observação

    Você será responsável por manter esse código atualizado com as últimas alterações adicionadas ao PnP.

Etapa 2: criar uma classe de trabalho de temporizador e adicionar sua lógica de trabalho de temporizador

  1. Adicione uma classe para o trabalho de temporizador chamado SimpleJob.

  2. Tenha a classe herdada da classe base abstrata TimerJob .

  3. No construtor, dê um nome ao trabalho do temporizador (base("SimpleJob")) e conecte o manipulador de eventos TimerJobRun .

  4. Adicione sua lógica de trabalho de temporizador ao manipulador de eventos TimerJobRun .

O resultado será semelhante ao seguinte:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using OfficeDevPnP.Core.Framework.TimerJobs;

namespace Core.TimerJobs.Samples.SimpleJob
{
    public class SimpleJob: TimerJob
    {
        public SimpleJob() : base("SimpleJob")
        {
            TimerJobRun += SimpleJob_TimerJobRun;
        }

        void SimpleJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
        {
            e.WebClientContext.Load(e.WebClientContext.Web, p => p.Title);
            e.WebClientContext.ExecuteQueryRetry();
            Console.WriteLine("Site {0} has title {1}", e.Url, e.WebClientContext.Web.Title);
        }
    }
}

Etapa 3: Atualizar Program.cs para usar o trabalho de temporizador

O trabalho de temporizador criado na etapa anterior ainda precisa ser executado. Para fazer isso, atualize Program.cs usando as seguintes etapas:

  1. Instancie sua classe de trabalho de temporizador.

  2. Forneça os detalhes de autenticação para o trabalho de temporizador. Este exemplo usa o nome de usuário e a senha para se autenticar no SharePoint Online.

  3. Adicione um ou mais sites para o programa de trabalho de temporizador acessar. Este exemplo usa um caractere cartão selvagem na URL. O trabalho de temporizador é executado em todos os sites que correspondem a essa URL de cartão selvagem.

  4. Inicie o trabalho de temporizador chamando o método Executar .

static void Main(string[] args)
{
    // Instantiate the timer job class
    SimpleJob simpleJob = new SimpleJob();

    // The provided credentials need access to the site collections you want to use
    simpleJob.UseOffice365Authentication("user@tenant.onmicrosoft.com", "pwd");

    // Add one or more sites to operate on
    simpleJob.AddSite("https://<tenant>.sharepoint.com/sites/d*");

    // Run the job
    simpleJob.Run();
}

Opções de implantação de trabalho de temporizador

A etapa anterior demonstra um trabalho de temporizador simples. A próxima etapa é implantar o trabalho de temporizador.

Um trabalho de temporizador é um arquivo .exe que deve ser agendado em uma plataforma de hospedagem. Dependendo da plataforma de hospedagem escolhida, a implantação é diferente. As seções a seguir descrevem as duas opções mais comuns da plataforma de hospedagem:

  • Usando o Azure como plataforma de hospedagem.
  • Usando o Windows Server como plataforma de hospedagem.

Implantar trabalhos de temporizador no Azure usando o Azure WebJobs

Antes de implantar um trabalho de temporizador, verifique se o trabalho pode ser executado sem interação do usuário. O exemplo neste artigo solicita que o usuário forneça uma senha ou segredo do cliente (veja mais na seção Autenticação ), que funciona durante o teste, mas não funciona quando implantado. Todos os exemplos existentes permitem que o usuário forneça uma senha ou segredo do cliente usando o arquivo app.config:

  <appSettings>
    <add key="user" value="user@tenant.onmicrosoft.com"/>
    <add key="password" value="your password goes here!"/>
    <add key="domain" value="Contoso"/>
    <add key="clientid" value="a4cdf20c-3385-4664-8302-5eab57ee6f14"/>
    <add key="clientsecret" value="your clientsecret goes here!"/>
  </appSettings>

Depois que essas alterações forem adicionadas ao arquivo app.config, execute o trabalho de temporizador do Visual Studio para confirmar se ele é executado sem interação do usuário.

A implantação real no Azure é baseada no Azure WebJobs. Para implantar este exemplo de trabalho de temporizador, siga estas etapas:

  1. Clique com o botão direito do mouse no projeto no Visual Studio e escolha Publicar como WebJob do Azure.

  2. Forneça uma agenda para o trabalho de temporizador e escolha OK.

  3. Escolha Sites do Microsoft Azure como um destino de publicação. Você será solicitado a entrar no Azure e selecionar o site do Azure que hospedará o trabalho de temporizador (você também pode criar um novo se isso for necessário).

  4. Escolha Publicar para enviar push do WebJob para o Azure.

  5. Após a publicação do trabalho de temporizador, você pode disparar o trabalho e marcar a execução do trabalho do Visual Studio ou do portal do Azure.

    portal do Azure (herdado)

  6. Além disso, o trabalho de temporizador pode ser executado no novo portal do Azure selecionando o trabalho e escolhendo Executar. Mais detalhes sobre como trabalhar com WebJobs no novo portal podem ser encontrados no artigo Executar tarefas em segundo plano com WebJobs em Serviço de Aplicativo do Azure.

    portal do Azure (atual)

Observação

Para obter diretrizes detalhadas sobre como implantar um WebJob do Azure, consulte Introdução ao Azure WebJobs (trabalhos de temporizador) para seus sites de Office 365.

Implantar trabalhos de temporizador no Windows Server usando o Agendador do Windows

Quando implantado no Windows Server, o trabalho de temporizador deve ser executado sem interação do usuário.

  1. Modifique o arquivo app.config conforme descrito na seção anterior Implantar trabalhos de temporizador no Azure usando o Azure WebJobs.

  2. Copie a versão de versão do seu trabalho para o servidor no qual você deseja que ele seja executado.

    Importante

    Copie todos os assemblies relevantes, o arquivo .exe e o arquivo .config para garantir que o trabalho possa ser executado no servidor sem instalar arquivos ou programas adicionais no servidor.

  3. Agende a execução do trabalho de temporizador. Recomendamos que você use o agendador de tarefas interno do Windows. Para usar o Agendador de Tarefas do Windows:

    1. Abra o Agendador de Tarefas (agendador Painel de Controle>Task).
    2. Escolha Criar Tarefa e especifique um nome e uma conta que executará a tarefa.
    3. Escolha Gatilhos e adicione um novo gatilho. Especifique a agenda desejada para o trabalho de temporizador.
    4. Escolha Ações e escolha a ação Iniciar um programa, selecione o trabalho do temporizador .exe arquivo e, em seguida, defina o início na pasta.
    5. Escolha OK para salvar a tarefa.

O Agendador de Tarefas do Windows

Estrutura de trabalho do temporizador em profundidade

Esta seção detalha os recursos da estrutura de trabalho do temporizador e como eles funcionam.

Structure

A classe TimerJob é uma classe base abstrata que contém as seguintes propriedades públicas, métodos e eventos:

A estrutura da classe TimerJob

A maioria das propriedades e métodos são explicados com mais detalhes nas próximas seções. O restante das propriedades e métodos são descritos aqui:

  • Propriedade IsRunning : obtém um valor que indica se o trabalho de temporizador está sendo executado. Valor de true se estiver executando; false se não estiver executando.
  • Propriedade Name : obtém o nome do trabalho de temporizador. O nome é inicialmente definido no construtor de trabalho do temporizador.
  • Propriedade SharePointVersion: obtém ou define a versão do SharePoint. Essa propriedade é definida automaticamente com base na versão do Microsoft.SharePoint.Client.dll carregado e, em geral, não deve ser alterada. No entanto, você pode alterar essa propriedade caso deseje usar as bibliotecas CSOM v16 em uma implantação v15 (local).
  • Propriedade versão : obtém a versão deste trabalho de temporizador. A versão é inicialmente definida no construtor de trabalho do temporizador ou é padrão como 1.0 quando não é definida por meio do construtor.

Para se preparar para uma execução de trabalho de temporizador, primeiro você deve configurá-lo:

  1. Forneça configurações de autenticação .
  2. Forneça um escopo, que é uma lista de sites.
  3. Opcionalmente, defina propriedades de trabalho de temporizador.

De uma perspectiva de execução, as seguintes etapas gerais são tomadas quando uma execução de trabalho de temporizador é iniciada:

  1. Resolver sites: URLs de site de cartão selvagens (por exemplo, https://tenant.sharepoint.com/sites/d*) são resolvidas em uma lista real de sites existentes. Se a expansão do subsite foi solicitada, a lista de sites resolvidos será expandida com todos os subsites.
  2. Crie lotes de trabalho com base nas configurações atuais de pisada e crie um thread por lote.
  3. Os threads executam lotes de trabalho e chamam o evento TimerJobRun para cada site na lista.

Mais detalhes sobre cada etapa podem ser encontrados nas próximas seções.

Autenticação

Antes que um trabalho de temporizador possa ser usado, o trabalho de temporizador precisa saber como se autenticar de volta ao SharePoint. Atualmente, a estrutura dá suporte às abordagens no enumeração AuthenticationType : Office365, NetworkCredentials e AppOnly. O uso dos métodos a seguir também define automaticamente a propriedade AuthenticationType como o valor apropriado do Office365, NetworkCredentials e AppOnly.

O fluxograma a seguir mostra as etapas a serem tomadas, seguidas por explicações detalhadas de cada abordagem.

Fluxograma das etapas de autenticação

Credenciais de usuário

Para especificar as credenciais do usuário para execução em Office 365, você pode usar esses dois métodos:

public void UseOffice365Authentication(string userUPN, string password)
public void UseOffice365Authentication(string credentialName)

O primeiro método aceita um nome de usuário e uma senha. O segundo permite especificar uma credencial genérica armazenada no Gerenciador de Credenciais do Windows. A captura de tela a seguir mostra a bertonline credencial genérica. Para usá-lo para autenticar o trabalho de temporizador, forneça bertonline como o parâmetro do segundo método.

O Gerenciador de Credenciais do Windows


Há métodos semelhantes para executar no SharePoint local:

public void UseNetworkCredentialsAuthentication(string samAccountName, string password, string domain)
public void UseNetworkCredentialsAuthentication(string credentialName)

Somente aplicativo

A autenticação somente aplicativo é o método preferencial porque você pode conceder permissões com escopo de locatário. Para credenciais de usuário, a conta de usuário deve ter as permissões necessárias.

Observação

Determinada lógica de resolução de site não funcionará com autenticação somente de aplicativo. Os detalhes podem ser encontrados na próxima seção.

Para configurar o trabalho para autenticação somente aplicativo, use um dos seguintes métodos:

public void UseAppOnlyAuthentication(string clientId, string clientSecret)
public void UseAzureADAppOnlyAuthentication(string clientId, string clientSecret)

O mesmo método pode ser usado para Office 365 ou SharePoint local, o que torna os trabalhos de temporizador que usam a autenticação somente aplicativo facilmente transportáveis entre ambientes.

Observação

Quando você usa a autenticação somente aplicativo, sua lógica de trabalho de temporizador falha quando AS APIs são usadas que não funcionam com AuthenticationType.AppOnly. Exemplos típicos são a API de Pesquisa, gravando no repositório de taxonomia e usando a API de perfil de usuário.

Sites para operar

Quando um trabalho de temporizador é executado, ele precisa de um ou mais sites para ser executado.

Adicionar sites a um trabalho de temporizador

Para adicionar sites a um trabalho de temporizador, use o seguinte conjunto de métodos:

public void AddSite(string site)
public void ClearAddedSites()

Para adicionar um site, especifique uma URL totalmente qualificada (por exemplo, https://tenant.sharepoint.com/sites/dev) ou uma URL de cartão selvagem.

Uma URL de cartão selvagem é uma URL que termina com um asterisco (*). Apenas um único * é permitido e deve ser o último caractere da URL. Uma URL de cartão selvagem de exemplo é https://tenant.sharepoint.com/sites/*, que retorna todas as coleções de sites sob o caminho gerenciado desse site. Para outro exemplo, https://tenant.sharepoint.com/sites/dev* retorna todas as coleções de sites em que a URL contém dev.

Normalmente, os sites são adicionados pelo programa que instancia o objeto de trabalho do temporizador, mas, se necessário, o trabalho de temporizador pode assumir o controle sobre a lista passada de sites. Faça isso adicionando uma substituição de método para o UpdateAddedSitesmétodo virtual, conforme mostrado no exemplo a seguir:

public override List<string> UpdateAddedSites(List<string> addedSites)
{
    // Let's assume we're not happy with the provided list of sites, so first clear it
    addedSites.Clear();

    // Manually adding a new wildcard Url, without an added URL the timer job will do...nothing
    addedSites.Add("https://bertonline.sharepoint.com/sites/d*");

    // Return the updated list of sites
    return addedSites;
}

Especificar credenciais de enumeração

Depois de adicionar uma URL de cartão selvagem e definir a autenticação somente para aplicativos, especifique as credenciais de enumeração. As credenciais de enumeração são usadas para buscar uma lista de coleções de sites usadas no algoritmo de correspondência do site para retornar uma lista real de sites.

Para adquirir uma lista de coleções de sites, a estrutura do temporizador se comporta de forma diferente entre Office 365 (v16) e local (v15):

  • Office 365: o método Tenant.GetSiteProperties é usado para ler as coleções de sites 'regulares'; a API de pesquisa é usada para ler as coleções de sites OneDrive for Business.
  • SharePoint local: a API de pesquisa é usada para ler todas as coleções de sites.

Dado que a API de pesquisa não funciona com um contexto de usuário, o trabalho de temporizador volta às credenciais de enumeração especificadas.

Para especificar as credenciais do usuário para execução em Office 365, você pode usar esses dois métodos:

public void SetEnumerationCredentials(string userUPN, string password)
public void SetEnumerationCredentials(string credentialName)

Há métodos semelhantes para executar no SharePoint local:

public void SetEnumerationCredentials(string samAccountName, string password, string domain)
public void SetEnumerationCredentials(string credentialName)

O primeiro método simplesmente aceita um nome de usuário, senha e, opcionalmente, domínio (quando no local). O segundo especifica uma credencial genérica armazenada no Gerenciador de Credenciais do Windows. Consulte a seção Autenticação para saber mais sobre o Gerenciador de Credenciais.

Expansão do subsite

Muitas vezes, você deseja que o código de trabalho do temporizador seja executado no site raiz da coleção de sites e em todos os subsites desse conjunto de sites. Para fazer isso, defina a propriedade ExpandSubSites como true. Isso faz com que o trabalho de temporizador expanda os subsites como parte da etapa de resolução do site.

Substituir sites resolvidos e/ou expandidos

Depois que a estrutura do temporizador resolve os sites de cartão selvagens e, opcionalmente, expande os subsites, a próxima etapa é processar a lista de sites. Antes de processar a lista de sites, talvez você queira modificar a lista de sites. Por exemplo, você pode querer remover sites específicos ou adicionar mais sites à lista. Isso pode ser feito substituindo o método virtual ResolveAddedSites . O exemplo a seguir mostra como substituir o método ResolveAddedSites para remover um site da lista.

public override List<string> ResolveAddedSites(List<string> addedSites)
{
    // Use default TimerJob base class site resolving
    addedSites = base.ResolveAddedSites(addedSites);

    //Delete the first one from the list...simple change. A real life case could be reading the site scope
    //from a SQL (Azure) DB to prevent the whole site resolving.
    addedSites.RemoveAt(0);

    //Return the updated list of resolved sites...this list will be processed by the timer job
    return addedSites;
}

Evento TimerJobRun

A estrutura de trabalho do temporizador divide a lista de sites em lotes de trabalho. Cada lote de sites é executado em seu próprio thread. Por padrão, a estrutura cria cinco lotes e cinco threads para executar esses cinco lotes. Consulte a seção Threading para saber mais sobre as opções de threading de trabalho do temporizador.

Quando um thread processa um lote, o evento TimerJobRun é disparado pela estrutura do temporizador e fornece todas as informações necessárias para executar o trabalho de temporizador. Os trabalhos do temporizador são executados como eventos, portanto, o código deve conectar um manipulador de eventos ao evento TimerJobRun :

public SimpleJob() : base("SimpleJob")
{
    TimerJobRun += SimpleJob_TimerJobRun;
}

void SimpleJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
{
    // your timer job logic goes here
}

Uma abordagem alternativa é usar um delegado embutido, conforme mostrado aqui:

public SimpleJob() : base("SimpleJob")
{
    // Inline delegate
    TimerJobRun += delegate(object sender, TimerJobRunEventArgs e)
    {
        // your timer job logic goes here
    };
}

Quando o evento TimerJobRun for acionado, você receberá um objeto TimerJobRunEventArgs , que fornece as informações necessárias para gravar a lógica de trabalho do temporizador. Os seguintes atributos e métodos estão disponíveis nesta classe:

A estrutura de classe TimerJobRunEventArgs

Várias das propriedades e todos os métodos são usados no recurso opcional de gerenciamento de estado, que é discutido na próxima seção. No entanto, as seguintes propriedades estão sempre disponíveis em todos os eventos, independentemente da configuração usada:

  • Propriedade url : obtém ou define a URL do site para o trabalho de temporizador para operar. Esse pode ser o site raiz da coleção de sites, mas também pode ser um subsite caso a expansão do site tenha sido feita.
  • Propriedade ConfigurationData : obtém ou define dados adicionais de configuração de trabalho do temporizador (opcional). Esses dados de configuração são transmitidos como parte do objeto TimerJobRunEventArgs .
  • Propriedade WebClientContext : obtém ou define o objeto ClientContext para a URL atual. Essa propriedade é um objeto ClientContext para o site definido na propriedade Url . Normalmente, esse é o objeto ClientContext que você usaria no código de trabalho do temporizador.
  • Propriedade SiteClientContext : obtém ou define o objeto ClientContext para o site raiz da coleção de sites. Essa propriedade fornece acesso ao site raiz caso o trabalho de temporizador exija acesso a ele. Por exemplo, o trabalho de temporizador pode adicionar um layout de página à galeria de páginas master usando a propriedade SiteClientContext.
  • Propriedade TenantClientContext : obtém ou define o objeto ClientContext para funcionar com a API do Locatário. Essa propriedade fornece um objeto ClientContext construído usando a URL do site de administrador de locatário. Para usar a API do Locatário no manipulador de eventos TimerJobRun do trabalho de temporizador , crie um novo objeto Tenant usando esta propriedade TenantClientContext .

Todos os objetos ClientContext usam as informações de autenticação descritas na seção Autenticação . Se você optou por credenciais de usuário, verifique se a conta usada tem as permissões necessárias para operar nos sites especificados. Ao usar somente aplicativo, é melhor definir permissões com escopo de locatário para a entidade somente aplicativo.

Gerenciamento de estado

Quando você grava a lógica do trabalho do temporizador, muitas vezes você precisa persistir o estado; por exemplo, para registrar quando um site foi processado pela última vez ou armazenar dados para dar suporte à lógica de negócios do temporizador. Por esse motivo, a estrutura de trabalho do temporizador tem recursos de gerenciamento de estado.

O gerenciamento de estado armazena e recupera um conjunto de propriedades padrão e personalizadas como uma cadeia de caracteres serializada JSON no saco de propriedades da Web do site processado (nome = nome do trabalho do temporizador + "_Properties"). A seguir estão as propriedades padrão do objeto TimerJobRunEventArgs :

  • Propriedade PreviousRun : obtém ou define a data e a hora da execução anterior.
  • Propriedade PreviousRunSuccessful : obtém ou define um valor que indica se a execução anterior foi bem-sucedida. Observe que o autor do trabalho de temporizador é responsável por sinalizar uma execução de trabalho como bem-sucedida definindo a propriedade CurrentRunSuccessful como parte da implementação do trabalho do temporizador.
  • Propriedade PreviousRunVersion : obtém ou define a versão do trabalho do temporizador da execução anterior.

Ao lado dessas propriedades padrão, você também tem a opção de especificar suas próprias propriedades adicionando pares palavra-chave-valor à coleção Properties do objeto TimerJobRunEventArgs. Para facilitar isso, há três métodos para ajudá-lo:

  • SetProperty adiciona ou atualiza uma propriedade.
  • GetProperty retorna o valor de uma propriedade.
  • DeleteProperty remove uma propriedade da coleção de propriedades.

O código a seguir mostra como o gerenciamento de estado pode ser usado:

void SiteGovernanceJob_TimerJobRun(object o, TimerJobRunEventArgs e)
{
    try
    {
        string library = "";

        // Get the number of admins
        var admins = e.WebClientContext.Web.GetAdministrators();

        Log.Info("SiteGovernanceJob", "ThreadID = {2} | Site {0} has {1} administrators.", e.Url, admins.Count, Thread.CurrentThread.ManagedThreadId);

        // grab reference to list
        library = "SiteAssets";
        List list = e.WebClientContext.Web.GetListByUrl(library);

        if (!e.GetProperty("ScriptFileVersion").Equals("1.0", StringComparison.InvariantCultureIgnoreCase))
        {
            if (list == null)
            {
                // grab reference to list
                library = "Style%20Library";
                list = e.WebClientContext.Web.GetListByUrl(library);
            }

            if (list != null)
            {
                // upload js file to list
                list.RootFolder.UploadFile("sitegovernance.js", "sitegovernance.js", true);

                e.SetProperty("ScriptFileVersion", "1.0");
            }
        }

        if (admins.Count < 2)
        {
            // Oops, we need at least 2 site collection administrators
            e.WebClientContext.Site.AddJsLink(SiteGovernanceJobKey, BuildJavaScriptUrl(e.Url, library));
            Console.WriteLine("Site {0} marked as incompliant!", e.Url);
            e.SetProperty("SiteCompliant", "false");
        }
        else
        {
            // We're all good...let's remove the notification
            e.WebClientContext.Site.DeleteJsLink(SiteGovernanceJobKey);
            Console.WriteLine("Site {0} is compliant", e.Url);
            e.SetProperty("SiteCompliant", "true");
        }

        e.CurrentRunSuccessful = true;
        e.DeleteProperty("LastError");
    }
    catch(Exception ex)
    {
        e.CurrentRunSuccessful = false;
        e.SetProperty("LastError", ex.Message);
    }
}

O estado é armazenado como uma única propriedade serializada JSON, o que significa que também pode ser usado por outras personalizações. Por exemplo, se o trabalho de temporizador escreveu a entrada de estado "SiteCompliant=false", uma rotina JavaScript poderá solicitar que o usuário aja porque o trabalho de temporizador determinou que o site estava incompatível.

Threading

A estrutura de trabalho do temporizador por padrão usa threads para paralelizar o trabalho. O threading é usado tanto para a expansão do subsite (quando solicitado) quanto para executar a lógica de trabalho do temporizador real (evento TimerJobRun ) para cada site. As seguintes propriedades podem ser usadas para controlar a implementação de threading:

  • Propriedade UseThreading : obtém ou define um valor que indica se o threading é usado. O padrão é verdadeiro. Defina como false para executar todas as ações usando o thread do aplicativo main.
  • Propriedade MaximumThreads : obtém ou define o número de threads a serem usados para este trabalho de temporizador. Os valores válidos são de 2 a 100. O padrão é 5. Ter muitos threads não é necessariamente mais rápido do que ter apenas alguns threads. O número ideal deve ser adquirido por meio de testes usando uma variedade de contagens de threads. O padrão de 5 threads foi encontrado para aumentar significativamente o desempenho na maioria dos cenários.

Limitação

Como um trabalho de temporizador usa threading e operações de trabalho de temporizador normalmente são operações com uso intensivo de recursos, uma execução de trabalho de temporizador pode ser limitada. Para lidar corretamente com a limitação, a estrutura de trabalho do temporizador e todo o PnP Core usa o método ExecuteQueryRetry em vez do método ExecuteQuery padrão.

Observação

É importante usar ExecuteQueryRetry no código de implementação de trabalho do temporizador.

Problemas de simultaneidade – processar todos os subsites de uma coleção de sites no mesmo thread

Trabalhos de temporizador podem ter problemas de simultaneidade ao usar vários threads para processar subsites.

Veja este exemplo: o Thread A processa o primeiro conjunto de subsites da coleção de sites 1 e o thread B processa o restante dos subsites da coleção de sites 1. Se o trabalho do temporizador processar o subsite e o site raiz (usando o objeto SiteClientContext ), poderá haver um problema de simultaneidade porque o thread A e o thread B processam o site raiz.

Para evitar o problema de simultaneidade (sem executar os trabalhos de temporizador em um único thread) use o método GetAllSubSites no trabalho de temporizador.

O código a seguir mostra como usar o método GetAllSubSites em um trabalho de temporizador:

public class SiteCollectionScopedJob: TimerJob
{
    public SiteCollectionScopedJob() : base("SiteCollectionScopedJob")
    {
        // ExpandSites *must* be false as we'll deal with that at TimerJobEvent level
        ExpandSubSites = false;
        TimerJobRun += SiteCollectionScopedJob_TimerJobRun;
    }

    void SiteCollectionScopedJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
    {
        // Get all the subsites in the site we're processing
        IEnumerable<string> expandedSites = GetAllSubSites(e.SiteClientContext.Site);

        // Manually iterate over the content
        foreach (string site in expandedSites)
        {
            // Clone the existing ClientContext for the sub web
            using (ClientContext ccWeb = e.SiteClientContext.Clone(site))
            {
                // Here's the timer job logic, but now a single site collection is handled in a single thread which
                // allows for further optimization or prevents race conditions
                ccWeb.Load(ccWeb.Web, s => s.Title);
                ccWeb.ExecuteQueryRetry();
                Console.WriteLine("Here: {0} - {1}", site, ccWeb.Web.Title);
            }
        }
    }
}

Registrar em log

A estrutura de trabalho do temporizador usa os componentes de log do PnP Core porque faz parte da biblioteca PnP Core. Para ativar o log interno do PnP Core, configure-o usando o arquivo de configuração apropriado (app.config ou web.config). O exemplo a seguir mostra a sintaxe necessária:

  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add name="DebugListenter" type="System.Diagnostics.TextWriterTraceListener" initializeData="trace.log" />
        <!--<add name="consoleListener" type="System.Diagnostics.ConsoleTraceListener" />-->
      </listeners>
    </trace>
  </system.diagnostics>

Usando o arquivo de configuração acima, a estrutura de trabalho do temporizador usa o System.Diagnostics.TextWriterTraceListener para gravar logs em um arquivo chamado trace.log na mesma pasta que o trabalho de temporizador .exe. Outros ouvintes de rastreamento estão disponíveis, como:

É altamente recomendável usar a mesma abordagem de registro em log para o código de trabalho de temporizador personalizado que você faz para a estrutura de trabalho do temporizador. No código de trabalho do temporizador, você pode usar a classe Log do PnP Core:

void SiteGovernanceJob_TimerJobRun(object o, TimerJobRunEventArgs e)
{
    try
    {
        string library = "";

        // Get the number of admins
        var admins = e.WebClientContext.Web.GetAdministrators();

        Log.Info("SiteGovernanceJob", "ThreadID = {2} | Site {0} has {1} administrators.", e.Url, admins.Count, Thread.CurrentThread.ManagedThreadId);

        // Additional timer job logic...

        e.CurrentRunSuccessful = true;
        e.DeleteProperty("LastError");
    }
    catch(Exception ex)
    {
        Log.Error("SiteGovernanceJob", "Error while processing site {0}. Error = {1}", e.Url, ex.Message);
        e.CurrentRunSuccessful = false;
        e.SetProperty("LastError", ex.Message);
    }
}

Confira também