Tarefas pendentes

A interface do sistema possui um controle de notificação de tarefas pendentes integrado ao menu de perfil do usuário. No ícone de abertura do menu é exibida a quantidade de tarefas pendentes e, ao abrir o menu, há a opção “Tarefas pendentes” que permite listar as tarefas pendentes do usuário logado no sistema.

Este controle é implementado por meio da tabela “Tarefas pendentes” (iPendingTask) e por scripts do tipo “x-pendingTasks” (.ipt). O controle implementado por padrão pelo Web Framework resume-se a uma listagem de tarefas para o usuário, no entanto, ele pode ser estendido ou substituído pelos demais módulos do sistema, permitindo a implementação de fluxos de trabalho mais elaborados. Este manual explica os conceitos da implementação padrão do sistema e os mecanismos que permitem a sua extensão e customização.

Configuração

A configuração do controle de tarefas pendentes é realizada na classe “/Configuração/Web Framework/Tarefas pendentes” por meio de arquivos do tipo “x-config” (.config). Abaixo são destacadas as principais propriedades que podem ser configuradas:

  • enabled: indica se o controle de tarefas está habilitado. Caso ele seja desativado, o sistema ocultará o ícone de tarefas pendentes e a opção “Tarefas pendentes” no menu de perfil do usuário.

  • tasksProcessKey: chave do processo que será aberto quando o usuário clicar na opção “Tarefas pendentes” do menu de perfil do usuário. O processo padrão do sistema lista apenas as tarefas existentes na tabela “iPendingTask” cujo campo “iGroupUser” está relacionado diretamente ao usuário ou indiretamente a um dos seus grupos ou papéis.

  • updateInterval: intervalo de atualização em milissegundos do contador de tarefas pendentes. Por padrão, é adotado um intervalo de 5 minutos.

  • getPendingTasksCount: função que recebe a chave de um usuário e é responsável por calcular a quantidade de tarefas pendentes para esse usuário. Essa função é executada pelo sistema em sessões “stateless”, portanto, a sua implementação não deve realizar caches associados ao usuário logado na sessão. Exemplo:

    var security = require('@nginstack/engine/context/security.js');
    var createSet = require('@nginstack/engine/lib/object/createSet.js');
    
    /** @type {DataSet} */
    let pendingTasks = null;
    
    this.getPendingTasksCount = function (userKey) {
      if (!pendingTasks) {
        pendingTasks = dbCache.getTable('iPendingTask');
      }
      const userAndGroupKeys = createSet(security.getUserAndGroupsKeys(userKey));
      let count = 0;
      for (pendingTasks.first(); !pendingTasks.eof; pendingTasks.next()) {
        const userAndGroups = pendingTasks.str('iGroupUser').split(',');
        const match = userAndGroups.some(function (key) {
          return key.trim() in userAndGroupKeys;
        });
        if (match) {
          count++;
        }
      }
    
      return count;
    };
    

Essas configurações normalmente não precisam ser alteradas, exceto quando se deseja desativar completamente a funcionalidade em uma base de dados, utilizando a propriedade enabled, ou para substituir o controle de tarefas padrão do sistema por uma outra implementação com mais funcionalidades ou com customizações avançadas. Nesse último cenário, é importante garantir que a implementação da função getPendingTasksCount retorne um valor coerente com a quantidade de tarefas listadas pelo processo configurado em tasksProcessKey.

Também é importante que as customizações sobre a implementação padrão do sistema respeitem o funcionamento de todos os campos definidos na classe de dados “/Dados/Sistema/Tarefas pendentes”, caso contrário, as tarefas criadas pelo sistema poderão não ser apresentadas corretamente nas interfaces customizadas de visualização de tarefas pendentes.

Scripts x-pendingTask (.ipt)

Os scripts de atualização de tarefas pendentes são criados nas classes de dados às quais as tarefas serão associadas. Eles são responsáveis por criar as tarefas pendentes em um DataSet temporário recebido por meio da propriedade this.iPendingTask. Esse DataSet não gera chaves, portanto o campo “iKey” não é preenchido nos registros criados pelos scripts e, para identificar unicamente uma tarefa no sistema, devem ser utilizados os campos “iTask” ou “iTaskUniqueId”.

Sempre que uma tarefa puder ser vinculada a um registro do sistema, deve-se dar preferência por atribuir a chave desse registro na coluna “iTask”. Caso não haja um vínculo direto entre uma tarefa e um registro, deve ser gravado no campo “iUniqueId” um identificador único que represente a tarefa. Esse identificador deve ser estável e gerado de forma determinística.

Após a execução de todos os scripts de geração de tarefas, o sistema sincroniza a tabela temporária de tarefas que foi populada pelos scripts com a tabela “iPendingTask” da base de dados. Para que esse sincronismo funcione, sem gerar alterações desnecessárias na base de dados, é fundamental que a lógica de geração de tarefas seja estável. Caso as condições do sistema não sejam alteradas entre duas execuções seguidas dos scripts, estas execuções devem gerar a mesma relação de tarefas, com as mesmas propriedades, em especial, com os mesmos identificadores utilizados nos campos “iTask” e “iTaskUniqueId”.

Além dos campos citados, a tabela “iPendingTask” possui diversos outros campos que devem ser utilizados de acordo com a necessidade de controle das tarefas pendentes. Seguem os mais relevantes:

  • iTaskClass: obrigatório e deve ser informado com a classe de dados associado à tarefa. Normalmente é utilizada a classe de dados onde o script “x-pendingTask” foi criado ou uma de suas filhas.
  • iDate e iHour: data e hora de criação da tarefa. Caso não sejam informados, serão definidos automaticamente pelo sistema.
  • iGroupUser: usuário ou grupo de usuários responsável pela tarefa.
  • iDescription: descrição da tarefa pendente. É recomendado que seja um texto curto, pois ele é apresentado na listagem de tarefas pendentes.
  • iProcessKey e iInteractionName: chave e nome da interação do processo responsável pela visualização da tarefa.
  • iParameterName: nome do parâmetro do processo que receberá a chave informada no campo “iTask”. Caso este campo não esteja preenchido, será utilizado o “iTaskUniqueId”.
  • iJSONParams: conjunto de parâmetros que serão informados ao processo, serializados no formato JSON.

A execução dos scripts de geração de tarefas pendentes é realizada pela classe PendingTaskManager de forma automática e a cada 5 minutos. O uso direto dessa classe não é recomendado, pois o seu uso indevido pode gerar custos desnecessários de processamento e conflitos de atualização.

Exemplo de um script de geração de tarefas pendentes:

// /Dados/Sistema/Engines/Alertas de Engines.ipt (-1891493390)

const EngineMonitor = require('@nginstack/engine/lib/monitoring/EngineMonitor.js');
const Groups = require('@nginstack/engine/keys/Groups.js');
const ClassKeys = require('@nginstack/engine/keys/Classes.js');

const pendingTasks = this.iPendingTask;
const monitor = new EngineMonitor();

const alerts = monitor.getAllAlerts();
alerts.forEach(function (alert) {
  pendingTasks.append();
  pendingTasks.setField('iTaskUniqueId', 'engine_alert_' + alert.code + '_' + alert.engineId);
  pendingTasks.setField('iTaskClass', ClassKeys.ENGINES);
  pendingTasks.setField('iDescription', alert.message);
  pendingTasks.setField('iGroupUser', Groups.ADMINISTRATORS);
  pendingTasks.setField('iProcessKey', -1891493485); // Engines.ip
  pendingTasks.setField('iJSONParams', JSON.stringify({
    engineId: alert.engineId
  }));

  pendingTasks.post();
});