Limpar filtro
Anúncio
Angelo Bruno Braga · Ago. 18, 2022
Olá Desenvolvedores,
Não percam esta sessão hands-on apresentada pelo @Donald.Woodlock, Vice Presidente Soluções para Saúde na InterSystems:
⏯ Machine Learning 201 - Redes Neurais e Reconhecimento de Imagens
Veja como treinar um modelo de Machine Learning para realizar Classificação de Imagens. Um dos problemas clássicos originais que o processo de machine learning tentava resolver por décadas era como distinguir um gato de um cachorro em fotos – algo que mesmo uma criança pequena consegue fazer mas era muito difícil para computadores. Depois de muitas décadas o problema foi resolvido pavimentando o caminho para o ML para agora podermos utilizá-lo na leitura de imagens de radiologia, identificação de rostos, identificação de tipos de objetos para carros autônomos, identificar desmatamento a partir de imagens de satélites e vários outros tipos de situações. Aprenderemos como isso é feito em uma sessão de hands-on. Em particular, trabalharemos sobre um problema baseado na identificação de dígitos escritos a mão. Construiremos, de forma sucessiva, modelos cada vez mais sofisticados para melhorar a acurácia desta tarefa utilizando Regressão Logística, We will build successively more sophisticated models to improve the accuracy of this task including Logistic Regression, uma Rede Neural Direta e uma Rede Neural Convolucional.
Esta é uma sessão de 2 horas que foi gravada ao vivo com poucos participantes. Não é necessária experiência em ML ou python mas se sentir a vontade em codificar pode ajudar.
Você precisará de uma conta do Kaggle (http://www.kaggle.com) para acompanhar o vídeo. Esta conta precisa ser 'verificada por telefone' para permitir oi uso das funcionalidades GPU do Kaggle, necessárias para um dos exercícios.
Os links que você precisará são: https://www.kaggle.com/competitions/digit-recognizerOs Notebooks estão neste link: http://www.donwoodlock.com/ml201/25Jul2022/index.html
Aproveitem e, fiquem ligados!
Artigo
Henrique Dias · Out. 26, 2020
Fala pessoal!
Quero dividir com vocês um projeto pessoal, que iniciou como um simples pedido no meu trabalho:
É possível saber quantas licenças Caché estamos utilizando?
Lendo outros artigos aqui na comunidade, eu encontrei este excelente artigo de David Loveluck
APM - Utilizando Caché History Monitorhttps://community.intersystems.com/post/apm-using-cach%C3%A9-history-monitor
Então, utilizando o artigo de David como base, eu comecei a utilizar o Caché History Monitor e a exibir todas as informações.Quando me deparei com o seguinte dilema: Qual a melhor tecnologia de frontend que eu posso usar?
Minha decisão acabou sendo pelo, bom e velho CSP, assim o cliente para qual estou trabalhando poderia se dar conta de que Caché é muito mais que MUMPS/Aplicações de Terminal.E depois de criar as páginas para exibir os históricos de licenças, crescimento de dataset e sessões CSP, eu resolvi me arriscar e imaginar um novo layout para System Dashboard e para página de Processos.Tudo funcionou perfeitamente com minha instância Caché.
Entretando, como isso ficaria no IRIS?
Seguindo outro ótimo artigo de Evgeny Shvarov
Using Docker with your InterSystems IRIS development repositoryhttps://community.intersystems.com/post/using-docker-your-intersystems-iris-development-repository
Passei a utilizar Docker no meu projeto e disponibilizei o código no Github, então agora, todos vocês podem usufruir do meu projeto seguindo alguns passos.
Como executar
Para iniciar a testar o código do repositório, basta você fazer o seguinte:
1. Faça o clone/git pull do repositório em algum diretório local$ git clone https://github.com/diashenrique/iris-history-monitor.git
2. Abra o terminal no diretório escolhido e execute:$ docker-compose build
3. Execute o container IRIS do seu projeto com o comando:$ docker-compose up -d
Como testar
Abra seu browser favorito e vá para:
Ex.: http://localhost:52773/csp/irismonitor/dashboard.csp
O usuário _SYSTEM pode executar o dashboard e outras funcionalidades.
System Dashboard
System Dashboard contém os seguintes itens:
Licença
Tempo Ativo
Erros de Aplicação
Processos Caché
Sessões CSP
Tabela de Lock
Espaço do Journal
Status do Journal
ECP AppServer
ECP DataServer
Write Daemon
Eficiência Caché
Alertas Sérios
O gráfico de linha, plota um ponto no gráfico a cada 5 segundos
System Menu
System Processes
Processes Filters
Use filtros diferentes para atingir o resultado que você precisa. Você também pode selecionar múltiplos filtros, pressione Shift + clicando no cabeçalho da coluna. E até exportar o datagrid para Excel!
History Monitor
O monitor de dados históricos para Sessões CSP e Licenciamento exibem informações divididas em 3 seções:
A cada 5 minutos
Diariamente
De hora em hora
Crescimento de dataset somente exibe as informações diárias.
As páginas de histórico compartilham as seguintes funcionalidades abaixo:
Seletor de intervalo de datas
O valor padrão é "Últimos 7 dias."
Gráfico / Data Table
No canto superior direito de cada seção existem 2 botões (Gráfico/Data Table)
O Data Table exibe a informação que alimenta o gráfico, e você ainda pode fazer download disso no formato Excel.
O arquivo excel exibe o mesmo formato, conteúdo e o agrupamento definido na página CSP.
Zoom
Todos os gráficos tem a opção de Zoom, para que a informação desejada, possa ser visualizada com maiores detalhes.
Média e Máximo
Nas seções Diariamente e De hora em hora, os gráficos exibem as informações Média/Máxima.
Média
Máxima
Aproveitem!
Artigo
Yuri Marx · Nov. 30, 2021
A InterSystems IRIS possui um ótimo sistema de auditoria. Ele é responsável por auditar eventos do sistema, mas você pode usá-lo para auditar seus aplicativos (ótimo recurso).
O sistema de auditoria é baseado no conceito de evento. Os eventos podem ocorrer com o IRIS ou em um aplicativo. Portanto, temos dois tipos de eventos para o sistema de auditoria:
1. Eventos do sistema: eventos ocorridos nos componentes IRIS da InterSystems (banco de dados, interoperabilidade, análise e core);
2. Eventos de usuário: evento ocorrido em aplicativos de usuário / empresa (seus), com os tipos de eventos de usuário criados (mapeados) por você no Portal de gerenciamento> Sistema> Gerenciamento de segurança> Eventos de usuário.
Para ver os eventos registrados pelos componentes do IRIS, vá para System Administration > Security > Auditing > Configure System Events. Os eventos do sistema começam com o caractere % + módulo IRIS (por exemplo,% Ensemble /% Production / StartStop,% System /% Login / Login). Se você clicar em Alterar status, poderá ativar ou desativar o tipo de evento do sistema.
Para ver o evento registrado por aplicativos de negócios (seus aplicativos), vá para System Administration > Security > Configure User Events. Você precisa modelar/registrar os tipos de eventos de seu aplicativo. O caractere % no início do nome da auditoria é reservado para os eventos de auditoria do sistema.
Todos os registros de auditoria são armazenados na tabela Security.Events Persitent Class / SQL. O nome do evento de auditoria possui 3 campos:
1. Fonte: fonte do evento (nome do aplicativo ou módulo);
2. Tipo: tipo de evento (tipo de dado ou tipo de característica);
3. Evento: nome do evento (nome da empresa, meio / descrição do evento).
Para consultar ou ver um relatório com registros de auditoria, vá para System Administration > Security > Auditing > View Audit Database. Veja:
No artigo, vou mostrar a você como fazer eventos de auditoria de usuário dentro do seu aplicativo, usando um aplicativo REST como exemplo. O aplicativo de amostra para ver os eventos de auditoria do usuário é: https://openexchange.intersystems.com/package/Audit-Mediator.
Siga estas etapas para o aplicativo de auditoria de amostra:
1. Clone o projeto
$ git clone git@github.com: yurimarx/iris-api-audit-mediator.git
2. Construa e faça o build o código-fonte do projeto
$ docker-compose up -d --build
3. Vá para Administration > Security > Auditing > Configure User Events4. Pressione o botão Create New Event5. Defina o Event Source: RESTAPI6. Defina o Event Type: solicitação7. Defina o Event Name: RESTAPI8. Pressione Save9. Preencha seu aplicativo Person com dados, chame o endpoint http://localhost:52773/crud/persons/populate10. Agora, ligue para http://localhost:52773/crud/persons/all ou qualquer outro endpoint11. Esta solicitação será registrada no banco de dados de auditoria12. Agora vá para System Administration > Security > Auditing > View Audit Database13. Procure as linhas com Event Source RESTAPI e Event Type Request e clique em Detail para ver os detalhes do registro de auditoria. Ver:
14. Clique em Details e veja:
O código fonte responsável por registrar a auditoria é:
SET tSC = $$$OK
TRY {
Set tSC = $SYSTEM.Security.Audit("RESTAPI","Request", "RESTAPI","URL: "_pUrl_". Method: "_pMethod_".","REST API request")
} CATCH ex {
SET tSC = ex.AsStatus()
}
Então, é muito fácil auditar, você deve usar a classe de método $SYSTEM.Security.Audit(). Veja mais detalhes em: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AAUDIT.
Artigo
Claudio Devecchi · Out. 13, 2020
##Introdução
Estamos na era da **economia multi-plataforma**, e as API's são a *"liga"* deste cenário digital. Sendo tão importantes, elas são encaradas por desenvolvedores como um **serviço** ou **produto** a ser consumido. Assim sendo, a **experiência** na sua utilização é um fator crucial de **sucesso**.
Visando melhorar esta experiência, padrões de especificação, como o [OpenAPI Specification (OAS)](https://swagger.io/specification/#:~:text=Introduction,or%20through%20network%20traffic%20inspection.) estão cada vez mais sendo adotados no desenvolvimento de API's RESTFul.
##O que é o IRIS ApiPub?
IRIS ApiPub é um projeto [Open Source](https://en.wikipedia.org/wiki/Open_source), que tem como principal objetivo **publicar** automaticamente **API's RESTful** criadas com a tecnologia [Intersystems IRIS](https://www.intersystems.com/try-intersystems-iris-for-free/), da forma mais simples e rápida possível, utilizando o padrão [Open API Specification](https://swagger.io/specification/) (OAS) versão 3.0.
Ele permite que o usuário foque principalmente na **implementação** e nas **regras de negócio** das API’s (Web Methods), abstraindo e automatizando os demais aspectos relacionados a **documentação, exposição, execução e monitoramento** dos serviços.

Este projeto também inclui uma implementação de exemplo completa (**apiPub.samples.api**) do *sample* [Swagger Petstore](https://app.swaggerhub.com/apis/Colon-Org/Swagger-PetStore-3.0/1.1), utilizado como *sample* oficial do [swagger](https://swagger.io/).
## Faça um teste com os teus serviços SOAP existentes
Se você já possui serviços SOAP publicados, você pode testar a sua publicação com Rest/JSON com OAS 3.0.

Ao publicar métodos com tipos complexos é necessário que a classe do objeto seja uma subclasse de %XML.Adaptor. Desta maneira serviços SOAP já construídos se tornam automaticamente compatíveis.

## Monitore as tuas API's com o IRIS Analytics
Habilite o monitoramento das API's para **administrar** e **rastrear** todas as *chamadas Rest*. Monte também os seus próprios indicadores.

## Instalação
1. Faça um *Clone/git pull* do repositório no diretório local.
```
$ git clone https://github.com/devecchijr/apiPub.git
```
2. Abra o terminal neste diretorio e execute o seguinte comando:
```
$ docker-compose build
```
3. Execute o container IRIS com o projeto:
```
$ docker-compose up -d
```
## Testando a Aplicação
Abra a URL do swagger http://localhost:52773/swagger-ui/index.html
Tente executar alguma API do Petstore, como fazer o *post* de um novo *pet*.
Veja o [dashboard do apiPub Monitor](http://localhost:52773/csp/irisapp/_DeepSee.UserPortal.DashboardViewer.zen?DASHBOARD=apiPub_Monitor_Dashboard/apiPub%20Monitor.dashboard). Tente fazer um drill down no domínio petStore para explorar e analisar as mensagens.
Mude ou crie metódos na classe [apiPub.samples.api](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/samples/api.cls) e volte a consultar a documentação gerada.
Repare que todas as mudanças são automaticamentes refletidas na documentação OAS ou nos schemas.
## **Publique sua API no padrão OAS 3.0 em apenas 3 passos:**
## Passo 1
Defina a classe de implementação das tuas API’s e **rotule** os métodos com o atributo [WebMethod]

*Caso você já possua alguma implementação com WebServices esse passo não é necessário.*
## Passo 2
Crie uma **subclasse** de apiPub.core.service e aponte a propriedade DispatchClass para a sua classe de Implementação criada anteriormente. Informe também o path de documentação OAS 3.0. Se desejar, aponte para a classe apiPub.samples.api (PetStore).

## Passo 3
Crie uma Aplicação Web e aponte a classe de Dispatch para a classe de serviço criada anteriomente.

## Utilize o Swagger
Com o [iris-web-swagger-ui](https://openexchange.intersystems.com/package/iris-web-swagger-ui) é possível expor a especificação do teu serviço. Basta apontar para o path de documentação e ... **VOILÁ!!**

## Defina o cabeçalho da especificação OAS

Há duas maneiras de definir o cabeçalho OAS 3.0:
A primeira é através da criação de um bloco JSON XDATA nomeado como *apiPub* na classe de implementação. Este método permite que se tenha mais de uma Tag e a modelagem é compatível com o padrão OAS 3.0. As propriedades permitidas para customização são *info, tags* e *servers*.
```
XData apiPub [ MimeType = application/json ]
{
{
"info" : {
"description" : "This is a sample Petstore server. You can find\nout more about Swagger at\n[http://swagger.io](http://swagger.io) or on\n[irc.freenode.net, #swagger](http://swagger.io/irc/).\n",
"version" : "1.0.0",
"title" : "IRIS Petstore (Dev First)",
"termsOfService" : "http://swagger.io/terms/",
"contact" : {
"email" : "apiteam@swagger.io"
},
"license" : {
"name" : "Apache 2.0",
"url" : "http://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"tags" : [ {
"name" : "pet",
"description" : "Everything about your Pets",
"externalDocs" : {
"description" : "Find out more",
"url" : "http://swagger.io"
}
}, {
"name" : "store",
"description" : "Access to Petstore orders"
}, {
"name" : "user",
"description" : "Operations about user",
"externalDocs" : {
"description" : "Find out more about our store",
"url" : "http://swagger.io"
}
} ]
}
}
```
A segunda maneira é através da definição de parâmetros na classe de implementação, assim como no exemplo a seguir:
```
Parameter SERVICENAME = "My Service";
Parameter SERVICEURL = "http://localhost:52776/apipub";
Parameter TITLE As %String = "REST to SOAP APIs";
Parameter DESCRIPTION As %String = "APIs to Proxy SOAP Web Services via REST";
Parameter TERMSOFSERVICE As %String = "http://www.intersystems.com/terms-of-service/";
Parameter CONTACTNAME As %String = "John Doe";
Parameter CONTACTURL As %String = "https://www.intersystems.com/who-we-are/contact-us/";
Parameter CONTACTEMAIL As %String = "support@intersystems.com";
Parameter LICENSENAME As %String = "Copyright InterSystems Corporation, all rights reserved.";
Parameter LICENSEURL As %String = "http://docs.intersystems.com/latest/csp/docbook/copyright.pdf";
Parameter VERSION As %String = "1.0.0";
Parameter TAGNAME As %String = "Services";
Parameter TAGDESCRIPTION As %String = "Legacy Services";
Parameter TAGDOCSDESCRIPTION As %String = "Find out more";
Parameter TAGDOCSURL As %String = "http://intersystems.com";
```
## Customize as tuas API's

É possível customizar vários aspectos das API's, como ***tags, paths e verbos***. Para tal, é necessária a utilização de uma notação específica, definida no comentário do método a ser customizado.
Sintaxe:
>***/// @apiPub[assignment clause]***
[*Method/ClassMethod*] *methodName(params as type) As returnType* {
>
>}
Todas as customizações dadas como exemplo nesta documentação estão disponíveis na classe [apiPub.samples.api](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/samples/api.cls).
## Customizando os Verbos
Quando não há nenhum tipo complexo como parâmetro de entrada, apiPub atribui automaticamente o verbo como *Get*. Caso contrário é atribuído o verbo *Post*.
Caso se queira customizar o método adiciona-se a seguinte linha nos comentários do método.
>/// @apiPub[verb="*verb*"]
Onde *verb* pode ser **get, post, put, delete ou patch**.
Exemplo:
>/// @apiPub[verb="put"]
## Customizando os Caminhos (Paths)
Esta ferramenta atribui automaticamente os *paths* ou o roteamento para os *Web Methods*. Ele utiliza como padrão o nome do método como *path*.
Caso se queira customizar o **path** adiciona-se a seguinte linha nos comentários do método.
>/// @apiPub[path="*path*"]
Onde *path* pode ser qualquer valor precedido com barra, desde que não conflita com outro *path* na mesma classe de implementação.
Exemplo:
>/// @apiPub[path="/pet"]
Outro uso bastante comum do path é definir um ou mais parâmetros no próprio path. Para tal, é necessário que o nome do parâmetro definido no método esteja entre chaves.
Exemplo:
>/// @apiPub[path="/pet/{petId}"]
Method getPetById(petId As %Integer) As apiPub.samples.Pet [ WebMethod ]
{
}
Quando o nome do parâmetro interno difere do nome do parâmetro exposto, pode-se equalizar o nome conforme exemplo a seguir:
>/// @apiPub[path="/pet/{petId}"]
/// @apiPub[params.pId.name="petId"]
Method getPetById(pId As %Integer) As apiPub.samples.Pet [ WebMethod ]
{
}
No exemplo acima, o parâmetro interno *pId* é exposto como *petId*.
## Customizando as Tags
É possível definir a **tag**(agrupamento) do método quando há mais que uma tag definida no cabeçalho.
>/// @apiPub[tag="*value*"]
Exemplo:
>/// @apiPub[tag="user"]
## Customizando o *Status Code* de Sucesso
Caso se queira alterar o *Status Code* sucesso do método, que é por padrão ***200***, utiliza-se a seguinte notação.
>/// @apiPub[successfulCode="*code*"]
Exemplo:
>/// @apiPub[successfulCode="201"]
## Customizando *Status Codes* de Exceção
Esta ferramenta assume como padrão o ***Status Code 500*** para quaisquer exceções. Caso se queira adicionar novos códigos para exceção na documentação, utiliza-se a seguinte notação.
>/// @apiPub[statusCodes=[{code:"*code*",description:"*description*"}]]
Onde a propriedade *statusCodes* é um array de objetos com código e descrição.
Exemplo:
> /// @apiPub[statusCodes=[
/// {"code":"400","description":"Invalid ID supplied"}
/// ,{"code":"404","description":"Pet not found"}]
/// ]
Ao disparar a exceção, Inclua o *Status Code* na descrição da exceção entre os sinais de "".
Exemplo:
> Throw ##Class(%Exception.StatusException).CreateFromStatus($$$ERROR($$$GeneralError, "****** Invalid ID supplied"))}
Veja o método ***getPetById*** da classe [apiPub.samples.api](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/samples/api.cls)
## Marcando a API como Descontinuada
Para que a API seja exposta como ***deprecated***, utiliza-se a seguinte notação:
>/// @apiPub[deprecated="true"]
## Customizando o *operationId*
Segundo a especificação OAS, ***operationId*** é uma string única usada para identificar uma API ou operação. Nesta ferramenta ela é utilizada para a mesma finalidade no [monitoramento e rastreamento](https://github.com/devecchijr/apiPub#monitore-a-chamada-das-suas-apis-com-o-iris-analytics) das operações.
Por padrão, ela recebe o mesmo nome do método da classe de implementação.
Caso se queira alterá-la utiliza-se a seguinte notação
>/// @apiPub[operationId="updatePetWithForm"]
## Alterando o charset do método
O charset padrão da geralmente é definido através do parâmetro CHARSET na classe de serviço, descrita no [Passo 2](https://github.com/devecchijr/apiPub#passo-2). Caso se queira customizar o charset de um método, deve se utilizar a seguinte notação:
>/// @apiPub[charset="*value*"]
Exemplo:
>/// @apiPub[charset="UTF-8"]
## Customizando nomes e outras funcionalidades dos parâmetros
Pode-se customizar vários aspectos de cada parâmetro de entrada e saída dos métodos, como por exemplo os nomes e as descrições que serão expostas para cada parâmetro.
Para se customizar um parametro específico utiliza-se a seguinte notação
>/// @apiPub[params.*paramId.property*="*value*"]
ou para respostas:
>/// @apiPub[response.*property*="*value*"]
Exemplo:
>/// @apiPub[params.pId.name="petId"]
/// @apiPub[params.pId.description="ID of pet to return"]
Neste caso, está sendo atribuido o nome *petId* e a descrição *ID of pet to return* para o parâmetro definido como *pId*
Quando a customização não é específica para um determinado parâmetro, utiliza-se a seguinte notação
>/// @apiPub[params.*property*="*value*"]
No exemplo abaixo, a descrição *This can only be done by the logged in user* é atribuída para todo o *request*, não apenas para um parâmetro:
>/// @apiPub[params.description="This can only be done by the logged in user."]
## Outras Propriedades que podem ser customizadas para parâmetros específicos
Utilize a seguinte notação para parâmetros de entrada ou saída:
>/// @apiPub[params.*paramId.property*="*value*"]
Para respostas:
>/// @apiPub[response.*property*="*value*"]
| Propriedade |
|----------------------------------------------------------------------------------------------------------------------------------------|
| ***required***: "true" se o parâmetro for requerido. Todos os parâmetros do tipo **path** já são automaticamente requeridos |
| ***schema.items.enum***: exposição de Enumeradores para tipos %String ou %Library.DynamicArray. Veja o método ***findByStatus*** da classe [apiPub.samples.api](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/samples/api.cls) |
| ***schema.default***: Aponta para um valor default para enumeradores. |
| ***inputType***: Por padrão é **query parameter** para os tipos simples e **application/json** para os tipos complexo (body). Caso se queira alterar o tipo de input, pode se utilizar este parâmetro. Exemplo de uso: Upload de uma imagem, que normalmente não é do tipo JSON. Veja método ***uploadImage*** da classe [apiPub.samples.api](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/samples/api.cls). |
| ***outputType***: Por padrão é **header** para os tipos %Status e **application/json** para o restante. Caso se queira alterar o tipo de output, pode se utilizar este parâmetro. Exemplo de uso: Retorno de um token ("text/plain"). Veja método ***loginUser*** da classe [apiPub.samples.api](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/samples/api.cls) |
## Relacione Schemas Parseáveis a tipos JSON Dinâmicos ***(%Library.DynamicObject)***

É possível relacionar [schemas OAS 3.0](https://swagger.io/docs/specification/data-models/) a [tipos dinâmicos](https://docs.intersystems.com/hs20201/csp/docbook/DocBook.UI.Page.cls?KEY=GJSON_create) internos.
A vantagem de se relacionar o schema com o parâmetro, além de informar ao usuário a especificação do objeto requerido, é o ***parsing automático*** do request é realizado na chamada da API. Se o usuário da API por exemplo enviar uma propriedade que não está no schema, enviar uma data em um formato inválido ou não enviar uma propriedade obrigatória, um ou mais erros serão retornados ao usuário informando as irregularidades.
O primeiro passo é incluir o schema desejado no bloco XDATA conforme exemplo abaixo. Neste caso o schema chamado *User* pode ser utilizado por qualquer método. Ele deve seguir as mesmas regras da modelagem [OAS 3.0](https://swagger.io/docs/specification/data-models/).
```
XData apiPub [ MimeType = application/json ]
{
{
"schemas": {
"User": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"username": {
"type": "string"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"phone": {
"type": "string"
},
"userStatus": {
"type": "integer",
"description": "(short) User Status"
}
}
}
}
}
}
```
O segundo passo é relacionar o nome do schema informado no passo anterior ao parâmetro interno do tipo [%Library.DynamicObject](https://docs.intersystems.com/hs20201/csp/docbook/DocBook.UI.Page.cls?KEY=GJSON_create) usando a seguinte notação:
>/// @apiPub[params.*paramId*.*schema*="*schema name*"]
Exemplo associando o parâmetro *user* ao schema *User*:
```
/// @apiPub[params.user.schema="User"]
Method updateUserUsingOASSchema(username As %String, user As %Library.DynamicObject) As %Status [ WebMethod ]
{
code...
}
```
Exemplo de request com erro a ser submetido. A propriedade username2 não existe no schema *User*. A propriedade id também não foi especificada e é requerida:
```
{
"username2": "devecchijr",
"firstName": "claudio",
"lastName": "devecchi junior",
"email": "devecchijr@gmail.com",
"password": "string",
"phone": "string",
"userStatus": 0
}
```
Exemplo de erro retornado:
```
{
"statusCode": 0,
"message": "ERRO #5001: Path User.id is required; Invalid path: User.username2",
"errorCode": 5001
}
```
Veja métodos ***updateUserUsingOASSchema*** e ***getInventory*** da classe [apiPub.samples.api](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/samples/api.cls). O método ***getInventory*** é um exemplo de schema associado à saída do método (response), portanto não é parseável.
### Gere o schema OAS 3.0 com base em um objeto JSON
Para auxiliar na geração do schema OAS 3.0, você pode usar o seguinte recurso:
**Defina** uma variável com uma amostra do objeto JSON.
```
set myObject = {"prop1":"2020-10-15","prop2":true, "prop3":555.55, "prop4":["banana","orange","apple"]}
```
**Utilize o método utilitário** da classe [apiPub.core.publisher](https://github.com/devecchijr/apiPub/blob/master/src/apiPub/core/publisher.cls) para gerar o schema:
```
do ##class(apiPub.core.publisher).TemplateToOpenApiSchema(myObject,"objectName",.schema)
```
**Copie e cole** o schema retornado no bloco XDATA:
Exemplo:
```
XData apiPub [ MimeType = application/json ]
{
{
"schemas": {
{
"objectName":
{
"type":"object",
"properties":{
"prop1":{
"type":"string",
"format":"date",
"example":"2020-10-15"
},
"prop2":{
"type":"boolean",
"example":true
},
"prop3":{
"type":"number",
"example":555.55
},
"prop4":{
"type":"array",
"items":{
"type":"string",
"example":"apple"
}
}
}
}
}
}
}
}
```
## Habilite o Monitoramento *(Opcional)*
1 - Adicione e ative os seguintes componentes na tua *Production* (*IRIS Interoperability*)
| Component | Type |
|----------------------|-------------------|
| apiPub.tracer.bm | Service (BS) |
| apiPub.tracer.bs | Service (BS) |
| apiPub.tracer.bo | Operation (BO) |
2 - Ative o monitoramento na classe descrita no [Passo 2](https://github.com/devecchijr/apiPub#passo-2)
O parâmetro ***Traceable*** deve estar ativado.
```
Parameter Traceable As %Boolean = 1;
Parameter TracerBSName = "apiPub.tracer.bs";
Parameter APIDomain = "samples";
```
O parâmetro ***APIDomain*** é utilizado para agrupar as API's no monitoramento.
3 - Importe os dashboards
```
zn "IRISAPP"
Set sc = ##class(%DeepSee.UserLibrary.Utils).%ProcessContainer("apiPub.tracer.dashboards",1)
```
Outros dashboards também podem ser criados com base no cubo ***apiPub Monitor***.
## Utilize esta ferramenta em conjunto com o Intersystems API Manager
Roteie as suas API's geradas e obtenha diversas vantagens com o [Intersystems API Manager](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_IAM)
## Compatibilidade
[ApiPub](https://github.com/devecchijr/apiPub#iris-apipub) é compatível com o produto [Intersystems IRIS](https://www.intersystems.com/products/intersystems-iris/) ou [Intersystems IRIS for Health](https://www.intersystems.com/products/intersystems-iris-for-health/) a partir da versão 2018.1.
## Repositório
***Github***: [apiPub](https://github.com/devecchijr/apiPub#iris-apipub) Parabéns @Claudio.Devecchi Artigo e aplicação excelentes!
Será de grande ajuda! Muito obrigado Henrique!
Artigo
Eduard Lebedyuk · Nov. 9, 2020
Neste artigo eu gostaria de falar sobre a abordagem de especificação primeiro (spec-first) para o desenvolvimento de APIs REST.
Embora o desenvolvimento de API REST com código primeiro (code-first) tradicional seja assim:
* Escrever o código
* Habilitando-o com REST
* Documentando-o (como uma API REST)
A especificação primeiro (spec-first) segue os mesmos passo, mas ao contrário. Começamos com uma especificação, também usando-a como documentação, geramos uma aplicação REST padrão a partir dela e, finalmente, escrevemos alguma lógica de negócios.
Isso é vantajoso porque:
* Você sempre tem uma documentação relevante e útil para desenvolvedores externos ou front-end que desejam usar sua API REST
* A especificação criada em OAS (Swagger) pode ser importada em uma variedade de ferramentas permitindo edição, geração de cliente, gerenciamento de API, teste de unidade e automação ou simplificação de muitas outras tarefas
* Arquitetura de API aprimorada. Na abordagem de código primeiro (code-first), a API é desenvolvida método a método então um desenvolvedor pode facilmente perder o controle da arquitetura geral da API, no entanto, com a especificação primeiro (spec-first), o desenvolvedor é forçado a interagir com uma API a partir da posição de um consumidor de API, o que geralmente ajuda no design de uma arquitetura melhor da API.
* Desenvolvimento mais rápido - como todo código padrão é gerado automaticamente, você não terá que escrevê-lo, tudo o que resta é desenvolver a lógica de negócios.
* Loops de feedback mais rápidos - os consumidores podem obter uma visão da API imediatamente e podem oferecer sugestões com mais facilidade, simplesmente modificando as especificações
Vamos desenvolver nossa API em uma abordagem de especificação primeiro!
### Plano
1. Desenvolver especificação no swagger
* Docker
* Localmente
* On-line
2. Carregar especificações no IRIS
* API REST de Gerenciamento de API
* ^REST
* Classes
3. O que aconteceu com a nossa especificação?
4. Implementação
5. Desenvolvimento adicional
6. Considerações
* Parâmetros especiais
* CORS
7. Carregar especificações no IAM
### Desenvolver especificação
O primeiro passo é, sem surpresa, escrever a especificação. O InterSystems IRIS oferece suporte à Especificação Open API (OAS):
> A **Especificação OpenAPI** (anteriormente Especificação Swagger) é um formato de descrição de API para APIs REST. Um arquivo OpenAPI permite que você descreva toda a sua API, incluindo:
>
> * Endpoints disponíveis (`/users`) e operações em cada endpoint (`GET /users`, `POST /users`)
> * Parâmetros de entrada e saída para cada operação
> * Métodos de autenticação
> * Informações de contato, licença, termos de uso e outras informações.
>
> As especificações das APIs podem ser escritas em YAML ou JSON. O formato é fácil de aprender e legível tanto para humanos como para máquinas. A Especificação OpenAPI completa pode ser encontrada no GitHub: [Especificação OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)
- da documentação Swagger.
Usaremos Swagger para escrever nossa API. Existem várias maneiras de usar o Swagger:
* [On-line](https://editor.swagger.io/)
* Docker: `docker run -d -p 8080:8080 swaggerapi/swagger-editor`
* [Instalação local](https://swagger.io/docs/open-source-tools/swagger-editor/)
Após instalar/executar o Swagger, você deverá ver esta janela em um navegador web:
No lado esquerdo, você edita a especificação da API e, à direita, vê imediatamente a documentação/ferramenta de teste da API renderizada.
Vamos carregar nossa primeira especificação de API nele (em [YAML](https://en.wikipedia.org/wiki/YAML)). É uma API simples com uma solicitação GET - retornando um número aleatório em um intervalo especificado.
Especificação da API matemática
swagger: "2.0"
info:
description: "Math"
version: "1.0.0"
title: "Math REST API"
host: "localhost:52773"
basePath: "/math"
schemes:
- http
paths:
/random/{min}/{max}:
get:
x-ISC_CORS: true
summary: "Get random integer"
description: "Get random integer between min and max"
operationId: "getRandom"
produces:
- "application/json"
parameters:
- name: "min"
in: "path"
description: "Minimal Integer"
required: true
type: "integer"
format: "int32"
- name: "max"
in: "path"
description: "Maximal Integer"
required: true
type: "integer"
format: "int32"
responses:
200:
description: "OK"
Aqui está seu conteúdo:
Informações básicas sobre nossa API e versão OAS usada.
swagger: "2.0"
info:
description: "Math"
version: "1.0.0"
title: "Math REST API"
Host do servidor, protocolo (http, https) e nomes de aplicações web:
host: "localhost:52773"
basePath: "/math"
schemes:
- http
Em seguida, especificamos um caminho (para que a URL completa seja `http://localhost:52773/math/random/:min/:max`) e o método de solicitação HTTP (get, post, put, delete):
paths:
/random/{min}/{max}:
get:
Depois disso, especificamos informações sobre nossa solicitação:
x-ISC_CORS: true
summary: "Get random integer"
description: "Get random integer between min and max"
operationId: "getRandom"
produces:
- "application/json"
parameters:
- name: "min"
in: "path"
description: "Minimal Integer"
required: true
type: "integer"
format: "int32"
- name: "max"
in: "path"
description: "Maximal Integer"
required: true
type: "integer"
format: "int32"
responses:
200:
description: "OK"
Nesta parte, definimos nossa solicitação:
* Habilita suporte a CORS (falarei mais sobre isso posteriormente)
* Fornece um _resumo_ e _descrição_
* O _operationId_ permite referência dentro das especificações, também é um nome de método gerado em nossa classe de implementação
* _produz_ - formato de resposta (como texto, xml, json)
* _parâmetros_ especificam parâmetros de entrada (sejam eles em URL ou corpo), no nosso caso especificamos 2 parâmetros - intervalo para nosso gerador de número aleatório
* _respostas_ lista respostas possíveis do servidor
Como você pode ver, este formato não é particularmente desafiador, embora haja muitos outros recursos disponíveis, aqui está uma [especificação](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md).
Finalmente, vamos exportar nossa definição como um JSON. Vá em File → Convert and save as JSON. A especificação deve ser semelhante a esta:
Especificação da API matemática
{
"swagger": "2.0",
"info": {
"description": "Math",
"version": "1.0.0",
"title": "Math REST API"
},
"host": "localhost:52773",
"basePath": "/math",
"schemes": [
"http"
],
"paths": {
"/random/{min}/{max}": {
"get": {
"x-ISC_CORS": true,
"summary": "Get random integer",
"description": "Get random integer between min and max",
"operationId": "getRandom",
"produces": [
"application/json"
],
"parameters": [
{
"name": "min",
"in": "path",
"description": "Minimal Integer",
"required": true,
"type": "integer",
"format": "int32"
},
{
"name": "max",
"in": "path",
"description": "Maximal Integer",
"required": true,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
}
}
}
### Carregar especificação no IRIS
Agora que temos nossas especificações, podemos gerar um código padrão para esta API REST no InterSystems IRIS.
Para passar para este estágio, precisaremos de três coisas:
* Nome da aplicação REST: pacote para nosso código gerado (utilizaremos `math`)
* Especificação OAS em formato JSON: acabamos de criá-la em uma etapa anterior
* Nome da aplicação WEB: um caminho base para acessar nossa API REST (`/math` em nosso caso)
Existem três maneiras de usar nossa especificação para geração de código, elas são essencialmente as mesmas e apenas oferecem várias maneiras de acessar a mesma funcionalidade
1. Chamar a rotina `^%REST` (`Do ^%REST` em uma sessão de terminal interativa), [documentação](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GREST_routine).
2. Chamar a classe `%REST` (`Set sc = ##class(%REST.API).CreateApplication(applicationName, spec)`, não interativa), [documentação](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GREST_objectscriptapi).
3. Usar a API REST de gerenciamento de API, [documentação](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GREST_apimgmnt).
Acho que a documentação descreve adequadamente as etapas necessárias, então apenas escolha uma. Vou adicionar duas notas:
* No caso (1) e (2) você pode passar a um objeto dinâmico, um nome de arquivo ou uma URL
* Nos casos (2) e (3) você **deve** fazer uma chamada adicional para criar uma aplicação WEB:: `set sc = ##class(%SYS.REST).DeployApplication(restApp, webApp, authenticationType)`, então em nosso caso, `set sc = ##class(%SYS.REST).DeployApplication("math", "/math")`, obter valores para o argumento `authenticationType` do arquivo de inclusão `%sySecurity`, entradas relevantes são `$$$Authe*`, então para um acesso não autenticado use `$$$AutheUnauthenticated`. Se omitido, o parâmetro padroniza para autenticação de senha.
### O que aconteceu com a nossa especificação?
Se você criou a aplicação com sucesso, um novo pacote `math` deve ter sido criado com três classes:
* _Spec_ - armazena a especificação no estado em que se encontra.
* _Disp_ - chamado diretamente quando o serviço REST é chamado. Ele empacota o tratamento REST e chama os métodos de implementação.
* _Impl_ - contém a implementação interna atual do serviço REST. Você deve editar apenas esta classe.
[Documentação](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GREST_intro#GREST_intro_classes) com mais informações sobre as classes.
### Implementação
Inicialmente, nossa classe de implementação `math.impl` contém apenas um método, correspondendo à nossa operação `/random/{min}/{max}`:
/// Obtenha um número inteiro aleatório entre min e max
/// Os argumentos do método contêm valores para:
/// min, número inteiro mínimo
/// max, número inteiro máximo
ClassMethod getRandom(min As %Integer, max As %Integer) As %DynamicObject
{
//(Place business logic here)
//Do ..%SetStatusCode()
//Do ..%SetHeader(,)
//Quit (Coloque a resposta aqui) ; a resposta pode ser uma string, uma stream ou um objeto dinâmico
}
Vamos começar com a implementação trivial:
ClassMethod getRandom(min As %Integer, max As %Integer) As %DynamicObject
{
quit {"value":($random(max-min)+min)}
}
E, finalmente, podemos chamar nossa API REST abrindo esta página no navegador: `http://localhost:52773/math/random/1/100`
A saída deve ser:
{
"value": 45
}
Também no editor Swagger, pressionando o botão `Try it out` e preenchendo os parâmetros da solicitação, também será enviada a mesma solicitação:
Parabéns! Nossa primeira API REST criada com uma abordagem de especificação primeiro (spec-first) está agora disponível!
### Desenvolvimento adicional
Claro, nossa API não é estática e precisamos adicionar novos caminhos e assim por diante. Com o desenvolvimento de especificação primeiro, você começa modificando a especificação, em seguida atualiza a aplicação REST (utilizando as mesmas chamadas que foram utilizadas para criar a aplicação) e finalmente escreve o código. Observe que as atualizações de especificações são seguras: seu código não é afetado, mesmo se o caminho for removido de uma especificação, o método não seria excluído da classe de implementação.
### Considerações
Mais notas!
#### Parâmetros especiais
A InterSystems adicionou parâmetros especiais à especificação swagger, aqui estão:
Nome
Tipo de Dado
Padrão
Local
Descrição
x-ISC_DispatchParent
classname
%CSP.REST
info
Super classe para a classe de despacho.
x-ISC_CORS
boolean
false
operation
Flag para indicar que requisições CORS para esta combinação endpoint/método deve ser suportada.
x-ISC_RequiredResource
array
operation
Lista separada por vírgulas dos recursos definidos e seus modos de acesso (recurso:modo) que são requeridos para acesso a este endponit do serviço REST. Exemplo: ["%Development:USE"]
x-ISC_ServiceMethod
string
operation
Nome do método de classe invocado internamente para atender a esta operação; o valor padrão é o operationId, o que é normalmente adequado.
#### CORS
Existem três maneiras de habilitar o suporte ao CORS.
1. Em uma rota na rota base, especificando `x-ISC_CORS` como verdadeiro (true). Isso é o que fizemos em nossa API REST de matemática.
2. Por API, adicionando
Parameter HandleCorsRequest = 1;
e recompilando a classe. Ele também sobreviveria à atualização das especificações.
3. (Recomendado) Por API, implementando a superclasse de dispatcher customizada (deve estender `%CSP.REST`) e escrevendo a lógica de processamento CORS lá. Para usar esta superclasse, adicione `x-ISC_DispatchParent` à sua especificação.
### Carregar especificações no IAM
Finalmente, vamos adicionar nossa especificação no IAM para que seja publicada para outros desenvolvedores.
Se você ainda não começou a utilizar o IAM, consulte [este artigo](https://community.intersystems.com/post/introducing-intersystems-api-manager). Ele também fala a respeito da disponibilização da API REST através do IAM, por isso não o descreverei aqui. Você pode querer modificar a especificação do `host` e os parâmetros do `basepath` para que eles apontem para o IAM, em vez de apontar para a instância InterSystems IRIS.
Abra o portal do administrador do IAM e acesse a aba `Specs` no espaço de trabalho relevante.
Clique no botão `Add Spec` e insira o nome da nova API (`math` em nosso caso). Depois de criar uma nova especificação no IAM, clique em `Edit` e cole o código da especificação (JSON ou YAML - não importa para o IAM):
Não se esqueça de clicar em `Update File`.
Agora nossa API está publicada para desenvolvedores. Abra o Portal do Desenvolvedor e clique em `Documentação` no canto superior direito. Além das três APIs padrão, nossa nova `API REST Math` deve estar disponível:
Abra-a:
Agora os desenvolvedores podem ver a documentação de nossa nova API e testá-la no mesmo lugar!
###
### Conclusão
O InterSystems IRIS simplifica o processo de desenvolvimento de APIs REST e, a abordagem de especificação primeiro (spec-first) permite um gerenciamento mais rápido e fácil do ciclo de vida das APIs REST. Com essa abordagem, você pode usar uma variedade de ferramentas para uma variedade de tarefas relacionadas, como geração de cliente, teste de unidade, gerenciamento de API e muitos outros.
### Links
* [Especificação OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)
* [Criação de serviços REST](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GREST)
* [Começando com IAM](https://community.intersystems.com/post/introducing-intersystems-api-manager)
* [Documentação IAM](https://docs.intersystems.com/irislatest/csp/docbook/apimgr/index.html)
Anúncio
Rochael Ribeiro · Mar. 3, 2022
Bem vindos aos lançamentos da Comunidade de Fevereiro de 2022!
Estamos gratos em apresentar nosso novo Calendário de Eventos da Comunidade para desenvolvedores InterSystems:
🎯 https://pt.community.intersystems.com/events
Neste calendário você verá o histórico de eventos da Comunidade de Desenvolvedores. Descubra mais sobre os eventos que estão acontecendo agora ou em breve, verifique os eventos que já ocorreram e assista às gravações dos webinars e encontros da Comunidade.
Vamos olhar em detalhe como utilizá-lo.
Para acessar o Calendário da Comunidade, clique no menu superior Eventos e vá para a seção Calendário de Eventos:
Neste calendário você encontrará os eventos disponíveis e já ocorridos, que podem ser ordenados em categorias:
Todos os eventos
Webinars
Encontros
Concursos
Clicando no modo "Pré-visualizar" do evento você verá seu anúncio:
Sintam-se a vontade para utilizar o modo "Lista", que apresenta as chamadas dos eventos com a opção de adicionar qualquer evento disponível ao seu calendário:
Você também pode selecionar qualquer data no calendário reduzido a direita para descobrir qual evento está agendado ou ocorreu naquele dia:
Além disto, você pode criar seu próprio evento clicando no botão "Novo evento". Você será automaticamente redirecionado para a página de criação de eventos.
❗️ Adicionar a tag Eventos a uma postagem irá abrir campos especiais para a criação de um evento:
Ao completar os campos com o nome do evento, link para realização do registro e horário, seu evento será automaticamente destacado na página principal, na área de eventos:
Você também verá no anúncio de seu evento:– uma área especial com o link para registro– um botão para adicionar rapidamente o evento ao seu calendário
Sintam-se a vontade para adicionar maiores detalhes sobre seus eventos adicionando uma descrição curta / link direto para participação / local.
Espero que tenham gostado das nossas atualizações!
Enviem suas solicitações de melhorias e bugs para o GitHub da Comunidade de Desenvolvedores ou coloque-as nos comentários desta postagem.
Fiquem atentos às novidades!
Artigo
Henrique Dias · Jul. 21, 2021
Conversando com um amigo especialista em Machine Learning @Renato.Banzai , um dos pontos que ele me passou e que hoje é um dos grandes desafios de Machine Learning das corporações é realizar o deploy de modelos de ML/AI em produção. InterSystems IRIS oferece IntegratedML, uma ótima solução para treinar, testar e realizar o deploy dos modelos ML/AI.
A parte mais complexa deste processo para criar modelos de ML/AI é fazer o tratamento dos dados, limpa-los, deixa-los confiáveis.
E é aí que tiramos proveito do poderoso padrão FHIR!
A ideia deste projeto é mostrar como podemos criar/treinar/validar modelos de ML/AI com FHIR e utilizar estes modelos treinados, com dados vindos de diferentes produções.
Acreditamos que este projeto tem um grande potencial e algumas das ideias a serem exploradas são:
Reuso/extensão de transformações DTL em outras bases de dados FHIR para modelos customizados de ML.
Utilizar transformações DTL para padronizar mensagens FHIR e publicar modelos ML como serviços
Criar uma espécie de repositório + regras de transformação para serem utilizados dentro de qualquer dataset FHIR. Ex.: pacotes zpm com modelos prontos.
Explorando as possibilidades que este projeto nos traz, podemos visualizar uma fonte de dados diferente.
Na imagem acima, o ponto FHIR Resource consumindo uma API REST, pode muito bem ser utilizada com FHIRaaS.
E não apenas utilizar o FHIRaaS on AWS, podemos também utilizar o novo serviço HealthShare Message Transformation Services, que automatiza a conversão de mensagens HL7v2 para FHIR.
Com essas pequenas demonstrações, visualizo esses recursos sendo muito bem aproveitados em cenários maiores, possibilitando e entregando com mais facilidade deploys em produção em ambientes realmente inovadores, como o AWS Healthlake. Por que não?!
Votação
Se você curtiu a ideia, curte o que estamos fazendo na comunidade, por favor vote em fhir-integratedml-example e nos ajude nessa jornada!
Artigo
Heloisa Paiva · Jun. 1, 2023
Esse é um artigo da página de "Perguntas frequentes" (FAQ) da InterSystems.
1. Exportar API
a. Use $system.OBJ.Export() para especificar rotinas individuais para exportar. Por exemplo:
do $system.OBJ.Export("TEST1.mac,TEST2.mac","c:\temp\routines.xml",,.errors)
O formato que você deve especificar é: NomeDaRotina.extensão, e a extensão pode ser: mac, bas, int, inc, obj.
Os erros durante a exportação se armazenam na variável "errors".
Veja a referência da classe %SYSTEM.OBJ para mais detalhes sobre $system.OBJ.Export().
b. Use $system.OBJ.Export() ao fazer uma exportação genérica usando * (wildcards). Por exemplo:
do $system.OBJ.Export("*.mac",c:\temp\allmacroutines.xml")
*Antes da versão 2008.1, utilize $system.OBJ.ExportPattern().
2. Importar API
a. Use $system.OBJ.Load() para importar todas as rotinas contidas no arquivo. Por exemplo:
do $system.OBJ.Load("c:\temp\routines.xml",,.errors)
b. Importe só algumas das rotinas contidas no arquivo
Observe o exemplo abaixo. Se quiser selecionar e importar somente algumas das rotinas inclusas no arquivo XML, coloque 1 no 5º argumento "listonly" numa primeira execução e carregue o arquivo XML com $system.OBJ.Load(), estabelecendo o 4º argumento (argumento de saída, list no exemplo abaixo). Isto criará uma lista de elementos na variável list. Depois poderemos recorrer essa lista e decidir que elementos (loaditem) queremos carregar, votando a executar $system.OBJ.Load() e indicando o elemento a carregar no 6º argumento. Você pode ver mais claramente neste exemplo:
Set file="c:\temp\routines.xml" // First get the list of items contained in the XML Do $system.OBJ.Load(file,,.errors,.list,1 /* listonly */) Set item=$Order(list("")) Kill loaditem While item'="" { If item["Sample" Set loaditem(item)="" { // Import only those containing Sample Set item=$Order(list(item)) } } // Execute import process with created list Do $system.OBJ.Load(file,,.errors,,,.loaditem)
Artigo
Danusa Calixto · Out. 10, 2022
No vasto e variado mercado de banco de dados SQL, o InterSystems IRIS se destaca como uma plataforma que vai muito além do SQL, oferecendo uma experiência multimodelo otimizada e a compatibilidade com um rico conjunto de paradigmas de desenvolvimento. Em especial, o mecanismo Object-Relational avançado ajudou as organizações a usar a abordagem de desenvolvimento mais adequada para cada faceta das cargas de trabalho com muitos dados, por exemplo, fazendo a ingestão de dados por objetos e consultando-os simultaneamente por SQL. As Classes Persistentes correspondem às tabelas SQL, suas propriedades às colunas da tabela, e a lógica de negócios é facilmente acessada usando as Funções Definidas pelo Usuário ou os Procedimentos Armazenados. Neste artigo, focaremos um pouco na mágica logo abaixo da superfície e discutiremos como isso pode afetar suas práticas de desenvolvimento e implantação. Essa é uma área do produto em que temos planos de evoluir e melhorar, portanto, não hesite em compartilhar suas opiniões e experiências usando a seção de comentários abaixo.
## Salvando a definição de armazenamento
Escrever uma nova lógica de negócios é fácil e, supondo que você tenha APIs e especificações bem definidas, adaptá-la ou ampliá-la também costuma ser. No entanto, quando não é apenas lógica de negócios, mas também envolve dados persistentes, qualquer coisa que você alterar na versão inicial precisará ser capaz de lidar com os dados que foram ingeridos por essa versão anterior.
No InterSystems IRIS, os dados e código coexistem em um único mecanismo de alto desempenho, sem a meia dúzia de camadas de abstração que você vê em outras estruturas de programação 3GL ou 4GL. Isso significa que há apenas um mapeamento muito fino e transparente para traduzir as propriedades da sua classe para posições $list em um nó global por linha de dados ao usar o armazenamento padrão. Se você adicionar ou remover propriedades, não quer que os dados de uma propriedade removida apareçam em uma nova propriedade. É desse mapeamento das propriedades da sua classe que a Definição de Armazenamento cuida, um bloco de XML um pouco enigmático que você deve ter percebido na parte inferior da definição da sua classe. Na primeira vez que você compila uma classe, uma nova Definição de Armazenamento é gerada com base nas propriedades e nos parâmetros da classe. Quando você faz alterações na definição da classe, no momento da recompilação, essas alterações são reconciliadas com a Definição de Armazenamento existente e alteradas para manter a compatibilidade com os dados existentes. Assim, enquanto você se esforça para refatorar as classes, a Definição de Armazenamento considera cuidadosamente sua criatividade anterior e garante que os dados antigos e novos permaneçam acessíveis. Chamamos isso de **evolução de esquema**.
Na maioria dos outros bancos de dados SQL, o armazenamento físico das tabelas é muito mais opaco, se visível, e as alterações só podem ser feitas por declarações `ALTER TABLE`. Esses são comandos de DDL (linguagem de definição de dados) padrão, mas normalmente são muito menos expressivos do que é possível alcançar ao modificar uma definição de classe e um código de procedimento diretamente no IRIS.
Na InterSystems, nos esforçamos para oferecer aos desenvolvedores do IRIS a capacidade de separar de forma limpa o código e os dados, pois isso é crucial para garantir o empacotamento e a implantação suave dos aplicativos. A Definição de Armazenamento desempenha uma função única nisso, pois captura como um mapeia para o outro. Por isso, vale a pena examinar mais a fundo o contexto de práticas gerais de desenvolvimento e pipelines de CI/CD em particular.
## Exportando para UDL
No século atual, o gerenciamento de código-fonte é baseado em arquivos, então vamos primeiro analisar o formato principal de exportação de arquivos do IRIS. A **Linguagem de Descrição Universal** (Universal Description Language ou UDL, na sigla em inglês) pretende, como o nome sugere, ser um formato de arquivo universal para todo e qualquer código que você escrever no InterSystems IRIS. É o formato de exportação padrão ao trabalhar com o plug-in VS Code ObjectScript e leva a arquivos fáceis de ler que parecem quase iguais ao que você veria em um IDE, com um arquivo .cls individual para cada classe (tabela) no seu aplicativo. Você pode usar $SYSTEM.OBJ.Export() para criar arquivos UDL explicitamente ou apenas aproveitar a integração do VS Code.
Da época do Studio, talvez você se lembre de um formato XML que capturava as mesmas informações do UDL e permitia agrupar várias classes em uma única exportação. Embora essa última parte seja conveniente em alguns cenários, é muito menos prático ler e rastrear diferenças entre versões, então vamos ignorá-la por enquanto.
Como a UDL é destinada a capturar tudo o que o IRIS pode expressar sobre uma classe, ela incluirá todos os elementos de uma definição de classe, incluindo a Definição de Armazenamento completa. Ao importar uma definição de classe que já inclui uma Definição de Armazenamento, o IRIS verificará se essa Definição de Armazenamento abrange todas as propriedades e índices da classe e, se for o caso, usará no estado em que está e substituirá a Definição anterior para essa classe. Isso torna a UDL um formato prático para o gerenciamento de versões das classes e a Definição de Armazenamento, pois preserva essa compatibilidade para dados ingeridos por versões anteriores da classe, onde quer que você implante.
Se você é um desenvolvedor hardcore, talvez se pergunte se essas Definições de Armazenamento continuam crescendo e se essa "bagagem" precisa ser transportada indefinidamente. O objetivo das Definições de Armazenamento é preservar a compatibilidade com dados pré-existentes, portanto, se você sabe que não há nada disso e quiser se livrar de uma genealogia longa, pode "redefinir" a Definição de Armazenamento ao removê-la da definição da classe e gerar outra com o compilador da classe. Por exemplo, você pode usar isso para aproveitar novas práticas recomendadas, como o uso de Conjuntos de Extensão, que implementam nomes globais com hash e separam cada índice em um próprio global, melhorando as eficiências de baixo nível. Para a compatibilidade com versões anteriores nos aplicativos dos clientes, não podemos mudar universalmente esses padrões na superclasse %Persistent (embora os aplicaremos ao criar uma tabela do zero usando o comando DDL `CREATE TABLE`). Portanto, uma revisão periódica das classes e do armazenamento vale a pena. Também é possível editar o XML de Definição de Armazenamento diretamente, mas os usuários precisam ter muito cuidado, pois isso pode tornar os dados existentes inacessíveis.
Até aqui, tudo bem. As Definições de Armazenamento oferecem um mapeamento inteligente entre suas classes e se adaptam automaticamente com a evolução do esquema. O que mais tem lá?
## Estático x Estatísticas?
Como você provavelmente sabe, o mecanismo SQL do InterSystems IRIS faz o uso avançado de estatísticas de tabela para identificar o plano de consulta ideal para qualquer declaração executada pelo usuário. As estatísticas de tabela incluem métricas sobre o tamanho de uma tabela, como os valores são distribuídos em uma coluna e muito mais. Essas informações ajudam o otimizador de SQL do IRIS a decidir qual índice é mais vantajoso, em que ordem unir as tabelas, etc. Portanto, intuitivamente, quanto mais atualizadas as estatísticas estiverem, maiores serão as chances de planos de consulta ideais. Infelizmente, até a introdução da amostragem de bloco rápida no IRIS 2021.2, coletar estatísticas de tabela precisas costumava ser uma operação computacionalmente cara. Portanto, quando os clientes implantavam o mesmo aplicativo em vários ambientes com padrões de dados basicamente iguais, fazia sentido considerar as estatísticas de tabela como parte do código do aplicativo e incluí-las nas definições da tabela.
Por isso, no IRIS hoje você encontra as estatísticas de tabela incorporadas à Definição de Armazenamento. Ao coletar estatísticas de tabela por uma chamada manual para `TUNE TABLE` ou de maneira implícita pela consulta (veja abaixo), as novas estatísticas são gravadas na Definição de Armazenamento e os planos de consulta existentes para essa tabela são invalidados, para que possam aproveitar as novas estatísticas durante a próxima execução. Por serem parte da Definição de Armazenamento, essas estatísticas farão parte das exportações de classe UDL e, portanto, podem acabar no seu repositório de código-fonte. No caso de estatísticas cuidadosamente verificadas para um aplicativo empacotado, isso é desejado, pois você quer que essas estatísticas específicas levem à geração do plano de consulta para todas as implantações do aplicativo.
A partir de 2021.2, o IRIS coletará automaticamente as estatísticas de tabela no início do planejamento de consulta ao consultar uma tabela que não possui nenhuma estatística e está qualificada para a amostragem de bloco rápida. Nos nossos testes, os benefícios de trabalhar com estatísticas atualizadas em vez de nenhuma estatística superaram claramente o custo da coleta de estatísticas em tempo real. Para alguns clientes, no entanto, isso teve o lamentável efeito colateral das estatísticas coletadas automaticamente na instância do desenvolvedor terminarem na Definição de Armazenamento no sistema de controle de fonte e, por fim, no aplicativo empacotado. Obviamente, os dados nesse ambiente de desenvolvedor e, portanto, as estatísticas nele talvez não sejam representativos para uma implantação real do cliente e levem a planos de consulta abaixo do ideal.
É fácil evitar essa situação. As estatísticas de tabela podem ser excluídas da exportação da definição de classe usando o qualificador `/exportselectivity=0` ao chamar $SYSTEM.OBJ.Export(). O padrão do sistema para essa sinalização pode ser configurado usando $SYSTEM.OBJ.SetQualifiers("/exportselectivity=0"). Depois, deixe para a coleta automática na eventual implantação coletar estatísticas representativas, tornar a coleta de estatísticas explícitas parte do processo de implantação, o que substituirá qualquer coisa que possa ter sido empacotada com o aplicativo, ou gerenciar suas estatísticas de tabela separadamente pelas próprias funções de importação/exportação: $SYSTEM.SQL.Stats.Table.Export() e Import().
A longo prazo, pretendemos mover as estatísticas de tabela para ficar com os dados, em vez de fazer parte do código, e diferenciar mais claramente entre quaisquer estatísticas configuradas explicitamente por um desenvolvedor e as coletadas de dados reais. Além disso, estamos planejando mais automação em relação à atualização periódica dessas estatísticas, com base em quanto os dados da tabela mudam ao longo do tempo.
## Conclusão
Neste artigo, descrevemos a função de uma Definição de Armazenamento no mecanismo ObjectRelational do IRIS, como ela é compatível com a evolução do esquema e o que significa incluí-la no seu sistema de controle de fonte. Também descrevemos por que as estatísticas de tabela são atualmente armazenadas nessa Definição de Armazenamento e sugerimos práticas de desenvolvimento para garantir que as implantações de aplicativos acabem com estatísticas representativas dos dados reais do cliente. Conforme mencionado anteriormente, planejamos aprimorar ainda mais esses recursos. Portanto, aguardamos seu feedback sobre a funcionalidade atual e planejada para refinar nosso design conforme apropriado.
Artigo
Vinicius Maranhao Ribeiro de Castro · Mar. 9, 2021
Introdução
Com a transformação digital no mundo dos negócios, novos recursos ou funcionalidades nos softwares oferecidos por uma empresa, podem significar vantagem competitiva. No entanto, se o time de TI não estiver preparado com a cultura, metodologia, práticas e ferramentas corretas, pode ser muito difícil garantir a entrega dessas novas funcionalidades a tempo hábil.
Integração contínua (do inglês “Continuous Integration”, CI) e entrega contínua (do inglês “Continuous Delivery”, CD) incorporam uma cultura, um conjunto de princípios operacionais e uma coleção de práticas que permitem que as equipes de desenvolvimento entreguem esses novos recursos ou novas funcionalidades com maior frequência e confiabilidade.
Neste artigo, veremos como criar e configurar uma esteira de CI/CD para uma aplicação desenvolvida na plataforma InterSystems IRIS utilizando serviços disponíveis na Amazon Web Services (AWS). Neste primeiro momento, vamos adaptar um workshop da própria AWS (link no final do artigo) porém, construindo e entregando um serviço REST implementado no InterSystems IRIS. Vamos ainda supor que este é um serviço “stateless”, ou seja, não há persistência de dados.
Serviços Utilizados e Arquitetura
Neste artigo, utilizaremos os seguintes serviços para compor nossa esteira de CI/CD:
GitHub: repositório de código
AWS Code Build: serviço responsável por fazer a construção (“build”) da aplicação
AWS Code Pipeline: serviço responsável por fazer a orquestração dos processos de construção (“build”) e implantação (“deploy”)
AWS Elastic Container Registry (ECR): repositório das imagens de container construídas
AWS Elastic Kubernetes Service(EKS): Cluster de Kubernetes gerenciado pela AWS
A arquitetura e interação entre os serviços descritos acima pode ser ilustrada pelo seguinte diagrama:
Desenvolvedores “comitam” código para o repositório do GitHub. Quando um “commit” é realizado, o AWS Code Pipeline detecta automaticamente as mudanças e começa a processá-las através da esteira definida
O AWS CodeBuild empacota as mudanças do código juntamente com qualquer dependência e constrói a imagem Docker. Opcionalmente, não abordado neste artigo, outro estágio da esteira testa o código e o pacote, também utilizando o AWS CodeBuild.
A imagem Docker construída é armazenada no AWS Elastic Container Registry (ECR) após uma construção e/ou teste bem sucedido.
AWS CodePipeline realiza a substituição da tag da imagem definida no manifesto de deployment da aplicação no Kubernetes para apontar para a imagem recém construída e chama a API do Kubernetes para fazer a atualização dos pods
O Kubernetes, neste caso o AWS Elastic Kubernetes Service (EKS), faz a atualização dos “pods” para rodar a imagem recém construída e disponibilizada no AWS ECR.
O serviço REST implementado no InterSystems IRIS será, portanto, um “pod” dentro do EKS. Neste artigo, reaproveitamos o projeto “iris-rest-api-template” desenvolvido pelo @Evgeny.Shvarov, disponível no github: https://github.com/intersystems-community/iris-rest-api-template
Este serviço implementa endpoints para criar, ler, atualizar ou remover uma pessoa (um registro da classe dc.Sample.Person).
Sem mais delongas, vamos pôr a mão na massa para criarmos uma esteira de CI/CD na prática com o InterSystems IRIS!
Criação dos serviços e projetos
Um pré-requisito para este projeto é possuir um cluster do EKS rodando. Para isso, é possível seguir essa documentação para entender como provisionar um cluster EKS na AWS:
https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html
A criação dos projetos do AWS Code Build e do AWS Code Pipeline será realizada através de um template do AWS Cloud Formation, assim como o repositório do ECR, o “bucket” do S3 e as “Policies” do Identity Access Manager da AWS. Esse template está disponibilizado no repositório deste artigo. O Cloud Formation é um serviço da AWS que permite modelar e configurar recursos da AWS a partir de um arquivo com essas definições, seguindo a metodologia de infraestrutura como código.
Pré-requisitos da AWS e do EKS
Para fazermos a implantação via esteira de CI/CD no EKS, há algumas configurações que precisamos fazer antes. Primeiramente, será necessário criar uma role no AWS Identity and Access Management (IAM) para permitir que o serviço do CodeBuild possa interagir com o EKS, já que o CodeBuild que executará o comando para fazer o “deploy” no EKS. Vamos fazer a criação desta “role” e adicionar uma “inline Policy” através do AWS CLI. Para informações sobre como instalar o AWS CLI, seguir esta documentação:
https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html
Com o AWS CLI instalado, executar os seguintes comandos:
TRUST="{ \"Version\": \"2012-10-17\", \"Statement\": [ { \"Effect\": \"Allow\", \"Principal\": { \"AWS\": \"arn:aws:iam::${ACCOUNT_ID}:root\" }, \"Action\": \"sts:AssumeRole\" } ] }"
echo '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "eks:Describe*", "Resource": "*" } ] }' > /tmp/iam-role-policy
aws iam create-role --role-name EksDemoSE --assume-role-policy-document "$TRUST" --output text --query 'Role.Arn'
aws iam put-role-policy --role-name EksDemoSE --policy-name eks-describe --policy-document file:///tmp/iam-role-policy
Agora que temos a “role” criada, é necessário adicionar esta role a ConfigMap aws auth no EKS. Para isso, execute os seguintes comandos (não remova espaços em branco):
ROLE=" - rolearn: arn:aws:iam::${ACCOUNT_ID}:role/EksDemoSE\n username: build\n groups:\n - system:masters"
kubectl get -n kube-system configmap/aws-auth -o yaml | awk "/mapRoles: \|/{print;print \"$ROLE\";next}1" > /tmp/aws-auth-patch.yml
kubectl patch configmap/aws-auth -n kube-system --patch "$(cat /tmp/aws-auth-patch.yml)"
Com isso, o CodeBuild já consegue interagir com o EKS através dos comandos “kubectl”.
Repositório GitHub
O próximo passo é criar um repositório no GitHub. É possível fazer um fork do repositório utilizado neste artigo para já criar um repositório juntamente com todos os arquivos necessários.
Para isso, basta fazer o login com sua conta do GitHub, acessar o repositório deste artigo em
https://github.com/vmrcastro/iris-rest-api-template
e clicar em Fork:
Para permitir o CodePipeline receber “callbacks” do GitHub, de forma que o gatilho para disparar a execução da nossa esteira de CI/CD seja quando um commit for feito para o repositório, é necessário gerar um token de acesso do GitHub.
Para isso acesse a página
https://github.com/settings/tokens/new
Marque a caixa “repo”
E clique no botão “Generate Token” no final da página.
Na página seguinte, copie o token gerado e grave em um lugar seguro. Necessitaremos dele nos próximos passos. Se atente para o fato de que este token é exibido somente uma vez após a criação e não é possível recuperá-lo posteriormente.
Criação e configuração do CodePipeline
Como havia sido mencionado anteriormente, a criação e configuração dos projetos do CodePipeline e do CodeBuild serão realizados através do Cloud Formation. Portanto, abra a console do Cloud Formation e clique em “Create Stack” e, em seguida, “With new resources (standard)”.
Na seção “Prepare Template”, deixe marcada a caixa “Template is ready” e, na seção “Specify Template”, marque a caixa “Upload template file”. Clique no botão “Choose file” e aponte para o arquivo “ci-cd-codepipeline.cfn.yml” na pasta “IaC” do projeto presente no repositório do GitHub. Em seguida, clique em “Next”.
Na tela seguinte, na seção “Stack name”, dê um nome para o projeto. Na seção “Parameters”, altere os campos de acordo com as instruções abaixo. Os campos não mencionados, devem continuar com o valor padrão.
GitHub
Username: seu username do GitHub
Access Token: Access Token para o Code Pipeline interagir com seu repositório do git, gerado no final da seção anterior deste artigo
Repository: o nome do seu repositório do GitHub. Neste caso, é o seu repositório oriundo do fork, demonstrado anteriormente neste artigo, cujo nome é “iris-rest-api-template”
Branch: defina qual será a branch que o CodePipeline ficará “ouvindo” para disparar a execução da esteira assim que houver um commit
EKS
EKS cluster name: nome do cluster de EKS já provisionado na AWS
Uma vez todos os campos preenchidos, clique em “Next”. Na tela seguinte, não é necessário fazer nenhuma alteração, somente clicar em “Next”. Finalmente, na última tela, confira os valores definidos e, se estiver tudo certo, marque a caixa “I acknowledge that AWS CloudFormation might create IAM resources.” e clique no botão “Create stack”.
Aguarde até o seu projeto do Cloud Formation ficar com o status de “CREATE_COMPLETE”:
Acompanhando a construção e entrega do projeto no Code Pipeline
Uma vez criado todos os recursos através do Cloud Formation, o processo de construção e implantação (“deploy”) é executado automaticamente pela primeira vez. Para acompanhar, vá até a console do Cloud Formation, expanda a seção “Pipeline” no menu esquerdo, clique em “Pipelines” e localize o seu projeto.
Se esta página foi aberta logo após a execução bem sucedida do Cloud Formation ou logo após um commit no seu repositório GitHub configurado no projeto, provavelmente o projeto estará com o status de “’In Progress”. Para acompanhar detalhes da execução, clique no nome do seu projeto, e a seguinte página deve abrir:
Na tela acima, podemos observar que a etapa “Source” foi executada com sucesso. Nesta etapa, o CodePipeline faz o download do repositório do GitHub configurado, armazena no S3 e disponibiliza para o CodeBuild executar a etapa “Build”, que está em execução. Clicando em “Details”, é possível acompanhar os logs da etapa, conforme mostrado na imagem a seguir:
Ainda é possível ficar “seguindo” os logs desta etapa, clicando no botão “Tail logs”:
Uma vez a etapa “Build” completada com sucesso, será possível observar o status “Succeded”:
O término com sucesso desta etapa significa que o projeto foi construído e foi feito o deploy no cluster de Kubernetes (EKS) configurado. Para verificarmos, podemos executar alguns comandos a partir de um “shell” que tenha o “kubectl” configurado para interagir com o EKS.
Primeiramente, vamos verificar se o deployment do nosso projeto, denominado “demose”, está rodando:
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
demosebr 1/1 1 1 131m
Podemos verificar também os pods que estão em execução e sua respectiva “idade”:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
demosebr-7f5dbdfb46-mkgsg 1/1 Running 0 2m8s
Aparentemente, nosso projeto foi entregue com sucesso ao EKS!
Vamos agora testar nosso serviço REST. Para isso, precisamos verificar o endereço do “service” do Kubernetes que será responsável por enviar requisições externas aos respectivos “pods”. Para isso, vamos executar o comando e copiar o conteúdo do campo da linha “demosebr” e da coluna “EXTERNAL-IP”. Este é o endereço para qual devemos enviar as requisições.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demosebr LoadBalancer 10.100.103.71 a2472[…]76.us-east-1.elb.amazonaws.com 52773:31752/TCP,1972:31866/TCP 130m
Veja que as portas expostas neste serviço foram a 52773 (webserver) e a 1972 (superserver). A configuração desse serviço é definida no arquivo “deploy.yml”, na raíz do nosso repositório.
Portanto, agora só resta enviar uma requisição para testar nosso serviço REST rodando no InterSystems IRIS. Para isso, eu utilizarei o cURL (mas utilize o cliente REST que você está mais habituado).
$ curl -v -u '_SYSTEM:SYS' -X POST 'http:// a2472[…]76.us-east-1.elb.amazonaws.com:52773/crud/persons/' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"Name":"Elon Mask","Title":"CEO","Company":"Tesla","Phone":"123-123-1233","DOB":"1982-01-19"}'
* Trying 52.[…].100:52773...
* TCP_NODELAY set
* Connected to a2472[…]76.us-east-1.elb.amazonaws.com (52.[…].100) port 52773 (#0)
* Server auth using Basic with user '_SYSTEM'
> POST /crud/persons/ HTTP/1.1
> Host: a2472[…]76.us-east-1.elb.amazonaws.com:52773
> Authorization: Basic X1NZU1RFTTpTWVM=
> User-Agent: curl/7.68.0
> accept: application/json
> Content-Type: application/json
> Content-Length: 94
>
* upload completely sent off: 94 out of 94 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 204 No Content
< Date: Mon, 08 Mar 2021 17:26:30 GMT
< Server: Apache
< CACHE-CONTROL: no-cache
< EXPIRES: Thu, 29 Oct 1998 17:04:19 GMT
< PRAGMA: no-cache
<
* Connection #0 to host a2472[…]76.us-east-1.elb.amazonaws.com left intact
E voilá! Recebemos o código HTTP 204 de resposta, então aparentemente o serviço REST está funcional e o “Elon Mask” foi cadastrado! Para termos certeza, vamos fazer outra requisição REST para listar todas as pessoas cadastradas, desta vez, sem o verbose do cURL para imprimirmos somente o corpo da resposta:
$ curl -u '_SYSTEM:SYS' -X GET 'http:// a2472[…]76.us-east-1.elb.amazonaws.com:52773/crud/persons/all' -H 'accept: application/json'
[{"Name":"Elon Mask","Title":"CEO","Company":"Tesla","Phone":"123-123-1233","DOB":"1982-01-19"}]
Como pode ser observado, o serviço REST do IRIS está 100% funcional!
Obs: Não utilize autenticação básica (usuário e senha) em requisições HTTP e não utilize o usuário _SYSTEM. Esta é uma configuração totalmente insegura.
Entendendo o funcionamento da esteira
Se você chegou até aqui, você pode estar se perguntando:
Como ou onde é definido as etapas para fazer a construção e implantação (“deploy”) do projeto?
Esta é uma excelente pergunta e você verá que as respostas estão em arquivos dentro do próprio repositório!
Tudo começa na definição da etapa “Build” do nosso projeto do CodePipeline. Esta etapa é definida pelo arquivo denominado “buildspec.yml”. Dentro deste arquivo, dividimos a etapa “Build” em 3 fases: “pre_build”, “build” e “post_build”. Cada fase irá conter um conjunto de comandos diferentes, também definidos dentro do mesmo arquivo.
Na fase de “pre_build”, basicamente definimos uma “tag” para a imagem do nosso serviço REST que estamos construindo, substituímos a string “CONTAINER_IMAGE” no arquivo “deploy.yml” pelo nome da imagem que estamos fazendo o build e fazemos o login no repositório de imagens Docker da AWS, o ECR, para posteriormente enviarmos a imagem construída para lá.
O arquivo “deploy.yml” mencionado anteriormente também está presente na raíz do repositório. Ele é o manifesto do Kubernetes, que indica todos os recursos que devem ser criados pelo Kubernetes para implantar nossa aplicação.
Já na fase de “build”, não há nenhuma novidade. É nela em que é feita a construção da imagem Docker da nossa aplicação através do comando “docker build”. Lembrando que este comando irá construir a imagem a partir do arquivo “Dockerfile”, também presente na raíz do projeto. Além de construir a imagem, estamos etiquetando com a “tag” definida na fase anterior.
Finalmente, na fase de “post_build”, fazemos o upload da imagem construída para o ECR, configuramos o kubectl para o EKS desejado e aplicamos o arquivo de manifesto do Kubernetes, o “deploy.yml”.
Considerações finais
Neste artigo prático foi abordado como construir uma esteira CI/CD para fazer a implantação do InterSystems IRIS no Kubernetes utilizando os serviços da AWS. A aplicação escolhida é simples e a implantação realizada não contempla alguns aspectos, como persistência de dados, por exemplo. O objetivo deste artigo é dar uma ideia dos primeiros passos para implementar uma esteira CI/CD. Caso tenha interesse, poste nos comentários deste artigo suas dúvidas ou detalhes que você deseja entender mais.
Até a próxima!
Fontes consultadas e utilizadas
https://community.intersystems.com/post/continuous-delivery-your-intersystems-solution-using-gitlab-part-i-git
https://www.eksworkshop.com/intermediate/220_codepipeline/
https://openexchange.intersystems.com/package/iris-rest-api-template
Anúncio
Angelo Bruno Braga · Ago. 4, 2022
Olá Desenvolvedores,
Vocês postaram 83 perguntas na Comunidade de Desenvolvedores em Julho:
Spoiler
InterSystems IRIS
Is there a way to use IRIS from command line (eg: batch file), the same way as it can be done in CACHE ?by Norman W. Freeman
INI parser/writer?by Eduard Lebedyuk
Cleaning up CacheStream Globalby Mark OReilly
Web teminal : lost connection with server (code 1006)by Jules Pontois
%JSONImport & TimeStampby Matjaz Murko
Convert UTC to Specific time zone, Objectscript onlyby Marcel den Ouden
How to add global nodes in management portal?by Jens Cheung
Delete first part of HL7 field up to first "(" characterby Jonathan Harris
ERROR #5540: SQLCODE: -99 Message: User UnknownUser is not privileged for the operationby Oliver Wilms
login failureby Oliver Wilms
Assigning Service or Process items as global values?by Jens Cheung
IRIS as a backend database for Java applicationby Oliver Wilms
Error compiling cache code on irisby Peter smit
How to use a variable in "{fieldName*C} "when using ObjectScript Trigger Codeby Yan Kevin
Can you help meHow to Convert HL7 input message into JSON Object Output Message by Smythe Smythee
Currently Running Processes with Mirroringby Gordon Sjostrom
What's the best way to structure a list of tuples for passing into a method?by Dominic Chui
About the callback method %OnSaveFinally()by Joseph Tsang
Dynamic SQL giving security errorby Peter smit
AWS EFS, EBS Shared e SQS Support?by Alfredo Neto
Blocking other streamlet types associated with a blocked Clinical Information Typeby Stella Ticker
IRIS SQL LOAD DATA <ERROR #5023: Remote Gateway Error: Connection cannot be established>by Jack Boulton
Handling StreamContainer in Business Processby Minoru Horita
Converting POSIX to ODBC timestamp in SQLby Timothy Leavitt
Webterminal broken :(by Kurro Lopez
How to get rid of gibberish in menu?by Iryna Mykhailova
%JSON.Adaptor and relationship propertyby Matjaz Murko
InterSystems - Database Management / Remote Connectivityby Erol Gurcinar
Can we integrate zen framework with Angular? If yes can anyone please help me in find out any resources for reference. by Prudhvi Arram
How to convert from internal date format to web formatby Yuri Marx
IRIS when is it safe to delete Journalsby Phillip Wu
Is there an equivalent to the Business Intelligence (BI) classes in IRIS ?by Norman W. Freeman
XSLT Samplesby Lesley Anderson
InterSystems IRIS for Health
How to access Production items through Objectscript?by Markus Suonpää
Given a Start Time, Time Zone and Duration (in Minutes): How to calculate End Timeby Victor Castanon
Iris for health, community, problems with new namespaces and productions.by Antti Suomi
Dynamically change output file name for a schedule taskby Marykutty George
iris health and Grafanaby Phillip Wu
Data showing as NULL in Power BI when it shouldn'tby Carla Davies
Can I create an User Account from codeby Joost Platenburg
Howto disable journaling temporarily for one database by Stefan Schick
Patient Labels Design Dilemma: ZPL Abstract Class vs JReport(LOGI)by Tom Cross
Installing IRISHealth_Community-2022.1.0.209.0-lnxubuntu2004x64 on Ubuntu 20.04 LTS on oracle virtual box by Jefferson Borges
Add REST Service Classes To VS Code Projectby Michael Davidovich
Do we have an option within Healthconnect to limit the number of messages sent at a time to downstream application from outboundby Praveen Bhoomiyal
%REST disp.cls, apps, and packages - How to structure?by Michael Davidovich
Opinions on CSP methods to REST services?by Michael Davidovich
HealthShare
MAXLEN usage for stringsby Ramesh Ramachandran
Custom hyperlink in Clinical Viewer (CV2)by Igor Titarenko
Data Quality Manager rebuild Cubesby Ephraim Malane
XML Projection when edit and resend- why not available to edit XML- custom classesby Mark OReilly
Configuration of Hub endpoints from UCR Edge by Ephraim Malane
Default Database Resource by Marykutty George
Open Exchange
Errors installing OpenExchange git-source-control using ZPMby Steve Pisani
Open Exchange Terminal in VSCodeby Yehuda Israel
Installing Apps without Dockerby Scott Roth
Ensemble
Exporting to Excel with %DisplayFormattedby Rochdi Badis
Shutdown Ensemble Business Service upon Warning in the Event Logby Jimmy Christian
Send zen report to file pathby Rochdi Badis
Crystal Report 2020 compatibility by Rochdi Badis
Bulk Testing Business Process (Rules)by Scott Roth
Deleted recordsby Rochdi Badis
Clone Classby Rochdi Badis
Empty HTTP responseby Rochdi Badis
Interoperability - Interface Mapsby Scott Roth
Dealing with single Quote in SQL Queryby Rochdi Badis
how to convert a docx file into pdf using Ensemble without using External librariesby Mohan Reddy
Inbound Adaptersby Rochdi Badis
Zen Page source urlby Rochdi Badis
Caché
HELP DOUBTS MSM-MUMPS-UNIXby Roger Andre
CSP event log errorby Paul Coviello
ASTM-XML | ASTM E1394 Specification anyone?by Patrick Halloran
Purge/Delete a RecordMap Batch before roll-over. by Blake Herlick
Dynamic SQL query on record that is lockedby MARK PONGONIS
SQL ODBC Warnings On Null Values in a Stored Procedureby Thembelani Mlalazi
Zen errorby Lowell Buschert
Laravel and Cache DBby Ramil TK
Problem converting Image to Base64by Fabio Care
How to obtain object value in DTL Trace Eventby Daniel Lee
VSCode
How i can test POST in Rest APIby Luiz Henrique Carvalho Martarelli
Syntax highlighting in VS Code markdownby Gertjan Klein
TrakCare
Trakcare Report development Using Object Scriptby Ramil TK
Documentation
Process XML documentby Adrian Izadpanah
E agora é a hora de anunciar as Perguntas Chave de Julho escolhidas pelos Especialistas InterSystems!
Estas perguntas serão destacadas com a tag #Key Question e seus autores irão receber o distintivo Key Question no Global Masters!
Então, aqui estão as perguntas escolhidas no mês de Julho de 2022:
📌 Delete first part of HL7 field up to first "(" character de @Jonathan.Harris
📌 Web teminal : lost connection with server (code 1006) de @Jules.Pontois8611
📌 Bulk Testing Business Process (Rules) de @Scott.Roth
📌 Interoperability - Interface Maps de @Scott.Roth
Obrigado pela contribuição!
Nos vemos no mês que vem! Continuem a mandar suas perguntas ;)
Artigo
Heloisa Paiva · Maio 29, 2023
Programação e suas linguagens
Ser um programador hoje em dia é basicamente uma versão nerd de ser um poliglota. Claro, a maioria de nós aqui na comunidade InterSystems "falamos ObjectScript". Entretando, eu acredito que essa não foi a primeira língua de muita gente. Por exemplo, eu nunca tinha ouvido falar nela antes de receber o treinamento apropriado na Innovatium.
A parte mais fascinante disso é que mesmo que sejamos aptos a aprender qualquer linguagem e nos tornar fluentes nela, sempre teremos nossas favoritas - as que nos sentimos mais confortáveis e familiares. Geralmente isso tem muito a ver com a primeira linguagem que aprendemos.
Pensando nisso, me deparei com a ideia Make JSON representation of messages in Interoperability message viewer instead of XML no portal de Ideias InterSystems e descobri que @Guillaume.Rongier7183 já resolveu isso para nós. Meu objetivo nesse artigo é mostrar como usar a solução dele e discutir sobre algumas utilidades.
O contexto
Para cada produção que construímos, o Portal de Administração do InterSystems IRIS cria uma interface que exibe todos os componentes conectados e cada mensagem relacionada a seu comportamento.
A figura acima ilustra o Portal de Configurações de Produção, onde você pode ver todos os Business Services, Processes e Operations, divididos em categorias de sua escolha. Para cada um, você pode checar e/ou alterar configurações gerais ou personalizadas, além de executar ações como mudar o estado, testar, exportar, checar os jobs, filas e logs relacionados a eles, etc. No entando, o que é mais importante para nós agora é a possibilidade de checar as mensagens.
Selecionando Mensagens na aba a direita, você poderá ver uma tabela com todas as mensagens relacionadas a essa produção. Ao mesmo tempo, se clicar em Ir Ao Visualizador de Mensagens você verá uma tabela mais detalhada com várias opções de filtros. Além disso, se escolher um componente Business antes de selecionar a aba de mensagens, verá apenas as mensagens da produção que se comunicam com o componente designado.
Nessa outra figura, podemos observar o Visualizador de Mensagens e finalmente resgatar a informação que queremos. Se selecionar uma linha na tabela, abrirá uma sessão a direita com todo detalhe possível sobre a mensagem escolhida. Isso significa que terá uma aba para a Header (cabeçalho), outra para o Body (corpo), mais uma para Tracing (rastreamento) e uma com um diagrama que mostra de onde a mensagem veio e os componentes relacionados. A aba que procuramos é a Contents (conteúdos).
A aba de conteúdos nos mostra uma versão em XML da mensagem e hoje vamos mudá-la para uma versão em JSON.
PS.: você também pode clicar no número da Sessão na tabela para obter uma visão focada do rastreamento ao lado da aba de Header, Body e Contents, como exemplificado na imagem abaixo
Desvio!
Essa sessão tem o objetivo de ser um pequeno desvio sobre o básico de construir uma API, um caso comum que utiliza muito JSON, e para familiarizar o contexto onde a aplicação pode ajudar.
Para trazer um sentimento real das alterações que essa aplicação promove, vamos construir um exemplo simples de uma API que recebe alguma informação numa request HTTP em formato JSON. Se já está familiarizado com APIs, sinta-se à vontade para pular para a próxima sessão, embora eu recomende pelo menos dar uma olhada nessa. Assim, você acompanhará melhor os exemplos discutidos a frente.
Eu vou seguir as boas práticas da Innovatium, mas lembre-se que esse não é o único jeito possível de fazer.
Primeiro, precisamos criar um service Dispatch, extendendo %CSP.REST e Ens.BusinessService, com o adaptador EnsLib.HTTP.InboundAdapter que lida requisições HTTP recebidas. Devemos especificar se o serviço lida com requisições CORS. Também podemos opcionalmente implementar o método de classe OnHandleOptionsRequest e finalmente definir um XData URlMap com parâmetros de Map, que dão seguimento para a próxima classe que vamos criar.
Class Sample.Service.Dispatch Extends (%CSP.REST, Ens.BusinessService)
{
Parameter HandleCorsRequest = 1;
Parameter ADAPTER = "EnsLib.HTTP.InboundAdapter";
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Map Prefix="/send" Forward="Sample.Service.Send"/>
</Routes>
}
ClassMethod GetService(Output tService As Ens.BusinessService) As %Status
{
Quit ##class(Ens.Director).CreateBusinessService(..%ClassName(1), .tService)
}
ClassMethod OnHandleOptionsRequest(url As %String) As %Status
{
; your code here
}
}
Então, no Portal de Administração criamos uma aplicação web com REST habilitado com a classe que acabamos de criar como a classe Dispatch.
Em seguida, desenvolvemos uma classe, que estende a Dispatch, com um XData UrlMap com parâmetros Route e construímos o método que vai de fato lidar com a requisição recebida. Isso também poderia ter sido feito direto no serviço de Dispatch. Através desse método, você pode fazer o que quiser com a requisição. No entanto, vamos focar em receber um JSON, transformá-lo em um objeto e enviar a um Business Operation que será responsável por lidar com a informação de qualquer forma necessária.
Class Sample.Service.Send Extends Sample.Service.Dispatch
{
Parameter CONTENTTYPE = "application/json";
Parameter CHARSET = "utf-8";
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Method="POST" Url="/message" Call="SendMessage"/>
</Routes>
}
ClassMethod SendMessage() As %Status
{
Set tSC = $$$OK
Try
{
#Dim %request As %CSP.Request
#Dim %response As %CSP.Response
#Dim Service As Ens.BusinessService
Set %response.ContentType = "application/json"
Set %response.CharSet = "utf-8"
; code for authentication - this part was cut out for simplification
; in this part I set the variables tUsername and tBasicAuth, used to create the request below.
; implementing authentication is optional, this is just an example
// creates service
Set tSC = ..GetService(.tService)
If $System.Status.IsError(tSC) Quit
// gets request body
Set tReceived = ##class(%Stream.GlobalCharacter).%New()
Set tSC = tReceived.CopyFrom(%request.Content)
If $System.Status.IsError(tSC) Quit
Set tMessage = ##class(%DynamicObject).%FromJSON(tReceived)
// creates request object for the business operation
Set tRequest = ##Class(Sample.Operation.SendMessage.Request).%New()
Set tRequest.Message = tMessage.message
Set tRequest.token = tBasicAuth
Set tRequest.Username = tUsername
Set tSC = tService.SendRequestSync("Sample.Operation",tRequest,.tResponse)
If $System.Status.IsError(tSC) Quit
// treats response
If $IsObject(tResponse)
{
Set tSC = tResponse.CopyToObject(.tJSON)
Quit:$$$ISERR(tSC)
}
Set tResult = ##class(%Stream.GlobalCharacter).%New()
Do tResult.Write(tJSON.%ToJSON())
Do tResult.OutputToDevice()
}
Catch Ex
{
Set tSC = Ex.AsStatus()
}
Quit tSC
}
}
É bom saber, mas por que eu deveria me incomodar?
Nessa sessão, vou tentar te convencer que é uma boa ideia ter a opção de mostrar o conteúdo de suas mensagens em formato JSON.
JSON é também legível por humanos, significando que você pode abrir um arquivo e ver o que está dentro dele sem ter que executá-lo por um parser Isso faz problemas de debug com seu código mais acessível e ajuda a documentar os dados recebidos de outras aplicações. (tradução livre)
É claro, às vezes "se sentir confortável" com uma linguagem não é suficiente para mudar algo na sua rotina de trabalho, afinal a mudança em si pode não ser confortável. No entanto, na API que acabamos de construir, há algumas outras coisas a se considerar além da questão de conveniência. Podemos notar que o código não foi escrito em XML em nada, então vê-lo nessa linguagem adicionaria um novo nível de complexidade.
Deixe-me explicar essa complexidade. Ainda que não pareça fazer uma grande diferença para um desenvolvedor ler uma simples mensagem com apenas uma propriedade string em tags (<tags>) ou formato JSON, também é importante fazer essa mensagem parecer familiar para os não-desenvolvedores que podem ter acesso a esse portal e devem ser capazes de entender de um modo geral o processamento da informação, já que JSON é muito mais amigável ao usuário. Além disso, quando as mesagens carregam propriedades de outros objetos ou tipos, somente serão enviadas adequadamente em JSON se têm a adaptação apropriada para isso. O IRIS torna isso fácil de resolver simplesmente estendendo a classe %JSON.Adaptor. Ao mesmo tempo, mensagens só aparecerão no Visualizador de Mensagens se têm a adaptação adequada para XML, que o IRIS também torna fácil estendendo %XML.Adaptor. Ainda assim, se o Visualizador de Mensagens mostrasse em JSON, esse último problema não existiria. De forma prática, isso significa diminuir a quantidade de dependências do projeto, o que, em idioma humano, significa reduzir o número de coisas que podem dar errado enquanto desenvolve e quando atualizações futuras do projeto ou até mesmo do IRIS saírem. E além de tudo, você não precisa de um time capacitado para lidar com XML.
Por fim, quando o time está procurando por erros e testando a API, você tem o formato exato da requisição recebida logada no Visualizador de mensagens, então é apenas uma questão de copiar e colar para testar em plataformas como Postman e outras para entender exatamente o que o sistema está lendo e escrevendo.
Se você quer saber ainda mais sobre os prós e contras de XML e JSON, eu recomendo fortemente que dê uma olhada no artigo json-vs-xml, que fornece uma incrível discussão sobre situações onde ambos são usados. A citação acima foi tirada desse website.
Ok, isso é demais! Me mostre como se usa!
Instalando
Você pode instalar com ZPM digitando no seu terminal no namespace desejado:
zpm "install objectscript-json-trace-viewer"
Outra opção é entrar no modo ZPM digitando zpm e então digitarinstall objectscript-json-trace-viewer
Se você não tem uma instância de IRIS na sua máquina, outra opção para testar é clonar o repositório e executar docker-compose build e então docker-compose up -d. Uma vez que tenha terminado de rodar o container, abra o link http://localhost:52777/csp/sys/UtilHome.csp?$NAMESPACE=DEMO e entre com usuário _SYSTEM e senha SYS para ver como funciona. Você também pode checar os códigos do repositório GitHub para exemplos de implementação.
Usando
Para cada classe que quer rastrear como JSON e não XML, adicione "Grongier.JsonTraceViewer.Message" para a lista de extensões ou qualquer de suas subclasses. Essa é a minha classe de Request do exemplo da última sessão:
Class Sample.Operation.SendMessage.Request Extends (Grongier.JsonTraceViewer.Request, Ens.Request)
{
Parameter XMLTYPE = "RequestSample";
Parameter RESPONSECLASSNAME = "Sample.Operation.SendMessage.Response";
Property Message As %String;
Property Username As %String;
Property token As %String;
}
Agora, ao chamar a API novamente, o Visualizador de Mensagens exibe o conteúdo como a imagem a seguir:
Erros que você pode enfrentar
Erro ao tentar executar o docker-compose build:
failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to create LLB definition: docker.io/store/intersystems/iris-community:2020.2.0.196.0: not found
SOLUCIONADO ao abrir a Dockerfile e mudar o valor de ARG IMAGE para uma imagem disponível no seu docker. Outra opção é usar a InterSystems extension de CaretDev e executar um pull na imagem iris-community mais recente. No meu caso, a primeira linha da Dockerfile ficou assim:
ARG IMAGE=containers.intersystems.com/intersystems/iris-community:2023.1.0.229.0
Erro ao tentar rodar o container:
#12 19.05 Error: ERROR #5001: Could not start SuperServer on port 1972, may be in use by another instance - Shutting down the system : $zu(56,2)=$Id: //iris/2023.1.0/kernel/common/src/journal.c#3 $ 10906 0Starting IRIS
failed to solve: executor failed running [/irissession.sh do $SYSTEM.OBJ.Load("Installer.cls", "ck") set sc = ##class(App.Installer).setup() do $system.OBJ.Load("/tmp/deps/zpm.xml", "ck") zn "DEMO"]: exit code: 225
SOLUCIONADO ao parar qualquer instância de IRIS existente na máquina e tentar rodar novamente.
Erro ao tentar rodar o container:
Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:52777 -> 0.0.0.0:0: listen tcp 0.0.0.0:52777: bind: An attempt was made to access a socket in a way forbidden by its access permissions.
SOLUCIONADO no Windows ao executar o terminal do sistema como administrador e rodar o comando a seguir. Esse erro pode ocorrer se a porta escolhida já estiver sendo usada. Você pode simplesmente alterá-lal no docker-compose.yml ou parar o processo que a esteja utilizando.
net stop hns
net start hns
Erro ao compilar classes personalizadas usando as classes deJsonTraceViewer:
Error #6281: XMLTYPE of Sample.Operation.SendMessage.Request class must be able to differentiate child classes of Grongier.JsonTraceViewer.Request.
> Error #5090: An error occurred while creating projection Grongier.JsonTraceViewer.Request:XMLEnabled.
SOLUCIONADO ao adicionar "Parameter XMLTYPE = 'type'" para toda classe que estende Grongier.JsonTraceViewer.Message, e alterando "type" por tipos únicos para cada classe.
Artigo
Guilherme Koerber · Dez. 21, 2021
Trabalhando com suporte, geralmente me perguntam por quantos dias devo manter um journals. Deve demorar dois dias ou depois de dois backups? Mais? Menos? Por que dois?
A resposta correta (para a maioria dos ambientes) é que você deve manter os journals desde o último backup validado. Ou seja, até que você não verifique se um backup é válido (restaurando o arquivo e verificando com o utilitário de integridade), você não pode ter certeza de que há uma boa cópia de seus dados e não pode limpar os journals com segurança.
Por exemplo, imagine que você precise restaurar seu sistema após uma falha de hardware que corrompeu alguns bancos de dados. A primeira etapa é ir aos últimos backups e restaurá-los. Mas, o que acontece se o backup for corrompido ou salvo em um disco com defeito? Você precisará procurar um backup anterior até encontrar uma cópia correta e limpa. Então, se você quiser se recuperar até o último momento, precisará aplicar os journals. Se você tiver apenas um ou dois dias, não será o suficiente e poderá perder dados.
A única maneira de ter certeza de que seus backups são válidos é verificando-os! E para verificar, quero dizer restaurar os bancos de dados e validar os dados neles. A maneira de verificar os dados dentro de um banco de dados é usando o utilitário Integrity.
Quando explico isso, a maioria dos administradores considera uma tarefa complexa, que leva muito tempo e é difícil de automatizar. Então, decidi construir um verificador / validador de backup super simples que ajuda você a validar backups facilmente. Estou enviando o utilitário para o site de troca aberta.
O utilitário é um verificador / validador de backup simples para backups feitos com o InterSystems Iris. Ele restaurará seu arquivo de backup (.cbk) automaticamente e executará um relatório de integridade posteriormente. Toda a "mágica" é feita no método restoreAll da classe Installer. Você pode pegar o código emprestado e melhorá-lo para enviar um e-mail quando terminar com os resultados.
Depois que o backup for restaurado e a verificação de integridade executada, o docker log (e messages.log) conterá os resultados da verificação de restauração e integridade. Os bancos de dados restaurados aparecerão em uma pasta Restaurar.
Pergunta
Fernando Beira · Mar. 2, 2022
Pessoal, tudo bem!?
Na instituição que trabalho estou enfrentando algo inusitado, temos duas instancias EC2 (AWS) em mirror e durante algum tempo em funcionamento a instância primaria nos lança um erro no message.log dizendo o seguinte (Journal Daemon has been inactive with I/O pending for 10 seconds) e em seguida efetua o chaveamento de máquina para o nó 2 da configuração, isso esta ocorrendo com uma frequência grande impactando a operação.
A infra diz que o link está com 50% de carga e em teoria não há gargalo na comunicação.
Trecho do message.log:
Sabem se pode ser alguma configuração relacionada aos discos virtuais da AWS?
Gostaria de saber se alguém já passou por esse tipo de situação? E como devemos proceder?
Desde já agradeço! Bom dia Fernando,
Você sabe qual foi o tipo de disco associado a estás máquinas EC2 na AWS?
Existem diversos tipos de discos lá inclusive os de baixa performance, se forem os do tipo magnético. Oi Djeniffer, obrigado pelo retorno!
Estamos com discos GP2 com block size de 4KB. Olá Fernando,
Seria importante realizar um teste utilizando discos do tipo gp3, pois o gp2 tem uma limitação bem especifica no "Max throughput per volume" e já tivemos problemas com ele devido a isso.
Aqui tem um link com estas diferenças entre os discos: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html Oi Djeniffer,
Compartilhei seu retorno com o pessoal que tem acesso a conta da AWS e descobrimos que a tempo atrás tivemos uma GMUD que realmente mudou o tipo do disco e efetuamos o rollback.
O ambiente está estável já a um dia e meio com poucas entradas no log, apenas do sincronismo do journal do mirror e alguns outros por menores, sem qualquer tipo de menção ao Deamon.
Agora, o que é interessante é que, segundo o Analista que efetuou a mudança dos discos, estávamos com o tipo GP3 e voltamos a usar o GP2 sem mexer em qualquer configuração de IOPS.
De qualquer forma criamos um ticket com a InterSystems para avaliação e seguimos monitorando daqui.
Muito obrigado pela ajuda!!
Olá Fernando,
Ótimo.
Pergunta
Guilherme Koerber · Set. 9, 2021
Olá comunidade!
Estou enfrentando um problema de crescimento da base, que está sendo gerado por um processo e por uma característica do Ensemble.
Ao executar o processo de limpeza das filas de mensagens o Ensemble “preserva” as Streams que fizeram parte dessas mensagens apagando somente o Header e Body. Desta forma a base de dados (de um dos namespaces) tem crescido cerca de 60GB por dia, o que vem estourando a capacidade do disco.
A InterSystems informou que isso se trata de uma característica e que está explicado nos documentos abaixo mencionados.
https://community.intersystems.com/post/ensemble-orphaned-messages
E também nesta parte da documentação: https://cedocs.intersystems.com/ens201812/csp/docbook/DocBook.UI.Page.cls?KEY=EGMG_purge_basic
Penso que o procedimento é implementar a remoção desses objetos tipo stream no método %OnDelete() da classe referente a essa mensagem, porém a complexidade dessa mensagem faz com que essa propriedade específica não seja alcançada pelo purge padrão. A stream não é exatamente o que tem no conteúdo, pois dentro dele você pode ter campos do tipo Stream, GlobalCharacterStream, etc.São esses campos que ele não apaga e ele deveria apagar. Pelo que entendi os dados ficam dentro de uma global chamada ^CacheStream e de lá elas nunca são apagadas.
Com isso estou tendo dificuldades em saber o que tem dentro dela, o que é de cada interface e o que ainda está sendo usado. Tendo em vista que ela não tem ligação direta com as classes de Stream.
Alguém já teve um problema assim que possa me auxiliar?
Desde já agradeço,
Guilherme Koerber. Olá Guilherme,
Na sua classe de mensagens você possui uma propriedade que aponta a outro objeto que possui stream ou a propriedade já é stream?
Pergunto pois já tive essa situação diversas vezes e resolvemos isso com uma mudança na classe de mensagens para não mais referenciar outros objetos. Djeniffer,De fato, esta apontado para um objeto. Irei tentar adaptar a classe para não referenciar mais objetos.Obrigado pela sugestão! =D Olá Guilherme,
Exato, o que fizemos aqui em algumas integrações foi converter o XML em uma FileCharacterStream e quando é necessário usar este objeto fazemos o correlate dele diretamente na BO, ai só existe o tráfego dessas streams e não mais dos objetos externos que dificultam o processo de limpeza.
Se precisar de alguma ajuda me informe.