Limpiar filtro
Artículo
Alberto Fuentes · 23 feb, 2023
Hola a todos!
Durante un proyecto necesitábamos poder definir temas sobre los que publicar mensajes, y crear diferentes subscriptores que recibiesen esos mensajes de forma asíncrona. Necesitábamos además que fuese lo más sencillo posible y que se pudiese utilizar directamente en InterSystems IRIS.
A modo de experimento os paso este [iris-pubsub](https://openexchange.intersystems.com/package/iris-pubsub).
# Infraestructura
Está construido sobre las funcionalidades de interoperabilidad de InterSystems IRIS, necesita tener una producción en marcha.
La primera vez que lo arranquemos definimos cuántas particiones queremos dedicar para atender mensajes. A mayor número de particiones, mayor capacidad. Por cada partición creará un Business Service y un Business Operation.
```
do ##class(dc.PubSub.API).AddPartitions(3)
```

# Temas (topics)
A continuación podemos crear temas o *topics* sobre los que queramos publicar mensajes. Opcionalmente se puede definir un `PartitionKey` que servirá para indicar qué campo del mensaje que publicamos se utilizará para decidir la partición lo gestionará. Los mensajes que se publican en una misma partición se procesan en orden.
Aquí creamos un tema llamado `simple/topic` e indicamos que la `PartitionKey` será el campo `patientId` de los mensajes que se publiquen.
```objectscript
set topic = ##class(dc.PubSub.API).CreateTopic("simple/topic", { "PartitionKey": "patientId" })
```
# Subscriptores
Ahora podemos crear subscriptores para el tema que hemos creado. Cuando se publique un mensaje en el tema o *topic* los subscriptores serán notificados.
Crearemos dos subscriptores que son dos *classmethod* de clases en ObjectScript. Una posible mejora sería poder definir subscriptores que fuesen endpoints HTTP.
```objectscript
do ##class(dc.PubSub.API).CreateSubscription("simple/topic", { "Protocol": "ClassMethod", "Endpoint": "USER:dc.PubSub.Test.Simple:Subscriber"})
do ##class(dc.PubSub.API).CreateSubscription("simple/topic", { "Protocol": "ClassMethod", "Endpoint": "USER:dc.PubSub.Test.Simple:Sub2"})
```
En este caso, los subscriptores son muy sencillos y sólo van a registrar información en la global `^zlog`:
```objectscript
ClassMethod Subscriber(payload As %String)
{
set obj = {}.%FromJSON(payload)
set ^zlog($i(^zlog)) = "["_$classname()_":Subscriber] Received: "_obj.%ToJSON()
}
ClassMethod Sub2(payload As %String)
{
set obj = {}.%FromJSON(payload)
set ^zlog($i(^zlog)) = "["_$classname()_":Sub2] Received: "_obj.%ToJSON()
}
```
# Publicar mensajes
Hemos creado un tema llamado `simple/topic` y hemos definido dos subscriptores. Vamos a publicar un par de mensajes:
```objectscript
do ##class(dc.PubSub.API).Publish("simple/topic", {"patientId": "HA98744455", "data": "dummy" } )
do ##class(dc.PubSub.API).Publish("simple/topic", {"patientId": "12TFFFHM88", "data": "dummy999" } )
```
Los mensajes podemos verlos en las trazas de interoperabilidad de IRIS:

Y si comprobamos la global `^zlog` donde los subscriptores guardan información, veremos lo siguiente:
```objectscript
USER>zw ^zlog
^zlog=4
^zlog(1)="[dc.PubSub.Test.Simple:Subscriber] Received: {""patientId"":""HA98744455"",""data"":""dummy""}"
^zlog(2)="[dc.PubSub.Test.Simple:Sub2] Received: {""patientId"":""HA98744455"",""data"":""dummy""}"
^zlog(3)="[dc.PubSub.Test.Simple:Subscriber] Received: {""patientId"":""12TFFFHM88"",""data"":""dummy999""}"
^zlog(4)="[dc.PubSub.Test.Simple:Sub2] Received: {""patientId"":""12TFFFHM88"",""data"":""dummy999""}"
```
¡Y esto es todo! Cualquier sugerencia o *pull-request* es bienvenida :)
Una pregunta, ¿se podría conseguir lo mismo con las clases ya preconstruidas en IRIS, en el paquete EnsLib.PubSub? Mmm exactamente lo mismo no lo sé, pero en el pasado hemos utilizado `EnsLib.PubSub` para alguna funcionalidad que necesitábamos pero terminábamos desarrollando nuestras propias clases para gestionar la complejidad que nos hacía falta.
De todas maneras, aún estamos experimentando con esta utilidad :)
Artículo
Eduardo Anglada · 5 abr, 2022
Si estás implementando más de un entorno/región/nube/cliente, inevitablemente te encontrarás con el problema de la gestión de la configuración.
Aunque todas (o solo varias de) tus implementaciones pueden compartir el mismo código fuente, algunas partes, como la configuración (ajustes, contraseñas) son diferentes de una implementación a otra y se deben gestionar de alguna manera.
En este artículo, intentaré ofrecer varios consejos sobre ese tema. Y comentaré principalmente las implementaciones de los contenedores.
##
## Unificación del código base
Antes de comenzar con la gestión de la configuración, hablemos de la unificación del código base. El problema es el siguiente: el código base _debe_ pretender, por lo general, confluir en una sola versión. Por supuesto, en cualquier momento, tendrás varias versiones de tu código base: la versión DEV con todas las nuevas características, la versión TEST con un código de prueba adicional, la versión PROD, y así sucesivamente. Y eso está _bien_ porque, en este ejemplo, los cambios se fusionan en una versión a lo largo del tiempo. Varias ramas de DEV se convierten en una rama de TEST y así sucesivamente.
El problema comienza cuando tenemos varias versiones en el paso final de nuestro *pipeline* de implementación. Por ejemplo, el cliente ABC pidió una característica particular XYZ, y ahora hay dos versiones del código base PROD - con la característica XYZ y sin ella. Esto es problemático ya que duplica inmediatamente nuestros tiempos de creación y el consumo de recursos. Claro, algunas veces no hay manera de hacerlo. Sin embargo, supongamos que tienes este tipo de divergencias persistentes en el código base. En ese caso, quizá merezca la pena investigar si se pueden agrupar en una sola versión; en este caso, la característica XYZ se activa o no cuando se inicia.
Dicho esto, vamos a la gestión de la configuración.
##
## Gestión de la configuración
¿Qué queremos?
* No almacenar todas las configuraciones posibles en un solo contenedor (es inseguro para uno, y aún debemos elegir de alguna manera qué configuración aplicar para otro)
* No crear un contenedor en cada configuración (simplifica el *pipeline* de CD)
Necesitamos transferir la configuración (ajustes, información confidencial, ...) durante el arranque de InterSystems IRIS y asignarla a nuestra aplicación.
## Transferencia de la configuración
Hay varias maneras de transferir la configuración al inicio.
### Variables de entorno
Rápido y fácil. En caso de que quieras almacenar todo en una variable, utiliza JSON para realizar la serialización. Además, recuerda que Windows tiene un límite de 32K caracteres en las variables de entorno (megabytes en Linux). Para recuperar variables de entorno utiliza [$SYSTEM.Util.GetEnviron("ENV\_VAR\_NAME")](https://docs.intersystems.com/iris20212/csp/documatic/%25CSP.Documatic.cls?&LIBRARY=%25SYS&CLASSNAME=%25SYSTEM.Util#GetEnviron). La principal ventaja es la facilidad de implementación. Además, verifica tu herramienta CD - por lo general, tiene algún tipo de soporte para variables de entorno durante la ejecución del *pipeline*, algunas veces con soporte de la información confidencial para que sea más seguro.
### Archivos montados
La configuración puede ser un archivo montado al inicio. La ventaja es que no tiene límites en la longitud. La desventaja es que no todas las ofertas de la nube son compatibles con los archivos montados, e incluso si lo hacen, la gestión de archivos puede ser más complicada que la gestión de las variables de entorno. Ten en cuenta que los archivos siempre se pueden recuperar de las capas antiguas de un contenedor, aunque se hayan eliminado en una capa posterior.
### Combinación en CPF
La configuración del sistema se puede transferir mediante un [Archivo Combinado de Configuración](https://docs.intersystems.com/iris20212/csp/docbook/DocBook.UI.Page.cls?KEY=ACMF). Y es una funcionalidad integrada. Desventaja: El Archivo de Combinación CPF no se encarga de la configuración a nivel de la aplicación.
### Docker/Información confidencial del CSP
Docker puede montar información confidencial como un archivo dentro de un contenedor. Las ofertas en la nube a menudo ofrecen una funcionalidad similar. Utilízalo en vez de los archivos sin formato para mejorar la seguridad.
## Análisis de la configuración
Bien, ya transmitiste la configuración dentro de un contenedor. ¿Y ahora qué? ¿Cómo la analizamos?
Hay varias opciones:
### %ZSTART
[%ZSTART](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GSTU_CUSTOMIZE_STARTSTOP) incluye tu código personalizado, que se ejecuta cuando se inicia el sistema. Por ejemplo:
SYSTEM
try {
new $namespace
set $namespace = "USER"
// apply configuration
set $namespace = "%SYS"
} catch ex {
zn "%SYS"
do ex.Log()
}
quit 1
Es importante tener en cuenta que %ZSTART se debe probar _completamente_, ya que InterSystems IRIS no se iniciará (o se comportará de forma errática) si la rutina %ZSTART devuelve un error.
Ahora ya estás preparado para aplicar tu configuración.
La forma de almacenar/aplicar la configuración a nivel de la aplicación depende, naturalmente, de la aplicación, pero [La configuración predeterminada del sistema](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ECONFIG_other#ECONFIG_other_default_settings_purpose ""){.editor-rtfLink} está disponible si utilizas la interoperabilidad. Incluso si no utilizas las producciones de interoperabilidad, puedes utilizar la configuración predeterminada del sistema, ya que está disponible para todo el mundo (siempre y cuando la interoperabilidad esté activada en un *namespace*).
Para crear una nueva configuración, ejecuta:
Set setting = ##class(Ens.Config.DefaultSettings).%New()
Set setting.ProductionName = production
Set setting.ItemName = itemname
Set setting.HostClassName = hostclassname
Set setting.SettingName = settingname
Set setting.SettingValue = settingvalue
Set setting.Description = description
Set sc = setting.%Save()
Y para recuperar la configuración, llama a cualquiera:
set sc = ##class(Ens.Config.DefaultSettings).%GetSetting(production, itemname, hostclassname, "", settingname, .settingvalue)
set settingvalue = ##class(Ens.Director).GetProductionSettingValue(production, settingname, .sc)
Los *hosts* de interoperabilidad reciben su configuración automáticamente al iniciar el trabajo del host empresarial.
## Resumen
Es fundamental que tu aplicación se pueda configurar cuando se implementa en más de un servidor. Puede ser bastante fácil en la primera parte del ciclo de desarrollo, pero se irá complicando a medida que la aplicación crezca. InterSystems IRIS ofrece varias herramientas que se pueden utilizar para configurar el estado de tu aplicación durante el arranque.
.
¿Cómo gestionas las implementaciones múltiples?
.
Artículo
Dmitry Maslennikov · 17 feb, 2023
Os presento mi nuevo proyecto: irissqlcli, REPL (Read-Eval-Print Loop) para InterSystems IRIS SQL.
Resaltado de sintaxis
Sugerencias (tablas, funciones)
+20 formatos de salida
Soporte a stdin
Salida a ficheros
Instalación con pip
pip install irissqlcli
O se puede ejecutar con docker
docker run -it caretdev/irissqlcli irissqlcli iris://_SYSTEM:SYS@host.docker.internal:1972/USER
Conexión a IRIS
$ irissqlcli iris://_SYSTEM@localhost:1972/USER -W
Password for _SYSTEM:
Server: InterSystems IRIS Version 2022.3.0.606 xDBC Protocol Version 65
Version: 0.1.0
[SQL]_SYSTEM@localhost:USER> select $ZVERSION
+---------------------------------------------------------------------------------------------------------+
| Expression_1 |
+---------------------------------------------------------------------------------------------------------+
| IRIS for UNIX (Ubuntu Server LTS for ARM64 Containers) 2022.3 (Build 606U) Mon Jan 30 2023 09:05:12 EST |
+---------------------------------------------------------------------------------------------------------+
1 row in set
Time: 0.063s
[SQL]_SYSTEM@localhost:USER> help
+----------+-------------------+------------------------------------------------------------+
| Command | Shortcut | Description |
+----------+-------------------+------------------------------------------------------------+
| .exit | \q | Exit. |
| .mode | \T | Change the table format used to output results. |
| .once | \o [-o] filename | Append next result to an output file (overwrite using -o). |
| .schemas | \ds | List schemas. |
| .tables | \dt [schema] | List tables. |
| \e | \e | Edit command with editor (uses $EDITOR). |
| help | \? | Show this help. |
| nopager | \n | Disable pager, print to stdout. |
| notee | notee | Stop writing results to an output file. |
| pager | \P [command] | Set PAGER. Print the query results via PAGER. |
| prompt | \R | Change prompt format. |
| quit | \q | Quit. |
| tee | tee [-o] filename | Append all results to an output file (overwrite using -o). |
+----------+-------------------+------------------------------------------------------------+
Time: 0.012s
[SQL]_SYSTEM@localhost:USER>
$ irissqlcli --help
Usage: irissqlcli [OPTIONS] [URI] [USERNAME]
Options:
-h, --host TEXT Host address of the IRIS instance.
-p, --port INTEGER Port number at which the IRIS instance is listening.
-U, --username TEXT Username to connect to the IRIS instance.
-u, --user TEXT Username to connect to the IRIS instance.
-W, --password Force password prompt.
-v, --version Version of irissqlcli.
-n, --nspace TEXT namespace name to connect to.
-q, --quiet Quiet mode, skip intro on startup and goodbye on
exit.
-l, --logfile FILENAME Log every query and its results to a file.
--irissqlclirc FILE Location of irissqlclirc file.
--auto-vertical-output Automatically switch to vertical output mode if the
result is wider than the terminal width.
--row-limit INTEGER Set threshold for row limit prompt. Use 0 to disable
prompt.
-t, --table Display batch output in table format.
--csv Display batch output in CSV format.
--warn / --no-warn Warn before running a destructive query.
-e, --execute TEXT Execute command and quit.
--help Show this message and exit.
o en el modo Python Embebido (requiere que %Service_CallIn esté habilitado)
$ irissqlcli iris+emb:///USER
Server: IRIS for UNIX (Ubuntu Server LTS for ARM64 Containers) 2022.2 (Build 368U) Fri Oct 21 2022 16:39:41 EDT
Version: 0.1.0
[SQL]irisowner@/usr/irissys/:USER>
Soporta stdin, así que se pueden canalizar algunos ficheros SQL con un grupo de consultas SQL y comandos irissqcli. Por ejemplo, este comando producirá 3 ficheros en diferentes formatos (de entre más de 20 formatos disponibles).
$ cat <<EOF | irissqlcli iris://_SYSTEM:SYS@localhost:1972/USER
.mode csv;
tee -o test.csv;
select top 10 TABLE_SCHEMA,TABLE_NAME
from information_schema.tables
order by TABLE_SCHEMA,TABLE_NAME;
notee;
.mode latex;
tee -o test.tex;
select top 10 TABLE_SCHEMA,TABLE_NAME
from information_schema.tables
order by TABLE_SCHEMA,TABLE_NAME;
notee;
.mode html;
tee -o test.html;
select top 10 TABLE_SCHEMA,TABLE_NAME
from information_schema.tables
order by TABLE_SCHEMA,TABLE_NAME;
notee;
EOF
Además, es posible ejecutar un terminal web con docker
docker run -d --name irissqlcli \
--restart always \
-p 7681:7681\
caretdev/irissqlcli-web irissqlcli iris://_SYSTEM:SYS@host.docker.internal:1972/USER
http://localhost:7681/
Y con docker-compose
version: '3'
services:
iris:
image: intersystemsdc/iris-community
ports:
- 1972
- 52773
command:
- -a
- '##class(Security.Users).UnExpireUserPasswords("*")'
cli:
image: caretdev/irissqlcli-web
ports:
- 7681:7681
environment:
- IRIS_HOSTNAME:iris
- IRIS_PORT=1972
- IRIS_NAMESPACE=USER
- IRIS_USERNAME=_SYSTEM
- IRIS_PASSWORD=SYS
Este artículo ha sido etiquetado como "Mejores prácticas" ("Best practices").
Los artículos con la etiqueta "Mejores prácticas" incluyen recomendaciones sobre cómo desarrollar, probar, implementar y administrar mejor las soluciones de InterSystems.
Artículo
Dani Fibla · 17 sep, 2020
¡Hola Comunidad!
Me gustaría compartir con vosotros mi experiencia sobre la depuración con Atelier.
Estoy desarrollando una API REST y quiero adjuntar un proceso cuando llamo a la API desde una herramienta cliente REST, por ejemplo Postman. El objetivo es inspeccionar valores del HEADER y el BODY de la solicitud HTTP durante el proceso de depuración.
Voy a demostrarlo usando una clase del namespace SAMPLES.
1 - Abre Atelier
2 - Abre tu clase de servicio REST
3- Ve al método relacionado con la URI que necesitas depurar
4- Agrega un HANG (sugiero de entre 10 y 15 segundos) que te permita poder adjuntar el proceso Caché / Ensemble. Observa la siguiente imagen:
5 - Cambia la vista al modo Depuración (DEBUG)
6 - Ve a Run->Debug Configurations->Application Atelier Attach
7 - Haz clic con el botón derecho en "Application Atelier Attach" y haz clic en New para configurar tu lista de proceso de servidor
8 - Configura tu lista de procesos del servidor Caché/Ensemble/Intersystems IRIS
9 - Haz clic en Apply
10 - Pásate a tu herramienta cliente REST
11 - Cuando llames a tu REST Api, retrasará (HANG) el proceso durante la cantidad de segundos que habías programado previamente
12 - En este momento, necesitarás volver a Atelier
13 - En Atelier, haz clic en Run->Debug Configuration->Application Atelier Attach y elige el proceso de la lista que configuraste
14 - Haz clic en Apply y cierra esta ventana
También puedes usar este pequeño botón como atajo:
En este punto, podrás depurar e inspeccionar tu código cuando lo necesites.
Por favor, no dejes de compartir tu experiencia y/o comentarios.
¡Gracias!
Artículo
David Reche · 2 feb, 2021
.png)
InterSystems IRIS es una excelente opción para desarrollar proyectos de aprendizaje automático (Machine Learning, ML), en escenarios de operaciones con datos masivos, debido a las siguientes razones:
1. Soporta el uso de shards para escalar el repositorio de datos, tal y como MongoDB por ejemplo.
2. Soporta la creación de cubos analíticos, y si unimos esto más el "sharding" nos permite tener volumen y rendimiento.
3. Soporta la recopilación de datos de forma planificada o en tiempo real, con una gran variedad de opciones de adaptadores de datos.
4. Permite automatizar todo el proceso de de-duplicación, utilizando lógica en Python u ObjectScript.
5. Permite organizar y automatizar el flujo de datos al repositorio, usando flujos visuales (BPL) y el Lenguaje para la transformación de datos (DTL).
6. Soporta el escalamiento automático avanzado, mediante Docker (IaC) y los scripts de Cloud Manager.
7. Soporta la carga de librerías ObjectScript *in provisioning*, mediante ZPM.
8. Dispone de interoperabilidad con Python y R para realizar ML en tiempo real.
9. Permite utilizar un motor AutoML, denominado IntegratedML para ejecutar el mejor algoritmo para el conjunto de datos indicados.
10. Permite crear análisis posteriores a la ejecución, como predicciones y clasificaciones de AutoML, salidas desde los procesos cognitivos de Python y R, tablas dinámicas de Inteligencia empresarial (BI), todo ello con visualizaciones propias o de terceros.
11. Permite crear vistas e informes avanzados con JReport.
12. Permite maximizar la reutilización y monetización de los datos con el API Management incluido.
Anuncio
Esther Sanchez · 25 mar, 2021
Hemos doblado el número de puntos concedidos por cada publicación y cada traducción que realicéis en la Comunidad de Desarrolladores. Así, desde el pasado día 18 de marzo, por cada artículo o pregunta, se obtienen:
✅ 200 puntos en la Comunidad de Desarrolladores en inglés (EN)✅ 400 puntos en las Comunidades de Desarrolladores en español (ES) / portugués (PT) / chino (CN) / japonés (JP)
y✅ ¡100 puntos por cada traducción!
*La promoción estará vigente durante un cierto período de tiempo.Además...
¿sabéis que se obtienen puntos extra por el primer artículo o la primera pregunta que publiquéis, y también por packs de artículos/preguntas? Echad un vistazo:
1er artículo
5 artículos
10 artículos
25 artículos
50 artículos
1 500 puntos extra
7 500 puntos extra
15 000 puntos extra
40 000 puntos extra
75 000 puntos extra
1ª pregunta
5 preguntas
10 preguntas
25 preguntas
50 preguntas
500 puntos extra
2 000 puntos extra
5 000 puntos extra
15 000 puntos extra
30 000 puntos extra
¡Y se obtienen insignias por cada uno de los packs de 5/10/25/50 artículos o preguntas!
Consulta la información adicional sobre Global Masters:
Cómo unirse a Global Masters
Descripción de las Insignias de Global Masters
Descripción de los Niveles de Global Masters
Si aún no perteneces al Programa de Fidelización de InterSystems, ¡te puedes dar de alta ahora mismo!
Si tienes alguna duda, puedes dejarnos un comentario en esta publicación y te responderemos al momento.
Anuncio
Esther Sanchez · 27 abr, 2021
¡Hola Comunidad!
Lo habéis pedido... y ya está aquí - ¡insignias por traducciones en Global Masters!
Nombre de la insignia
Reglas
DC Translator
Conseguida por 1 traducción
Insignia del 2º nivel (Advocate)
Traducciones de inglés a cualquier otro idioma de la Comunidad (español, portugúes, chino y japonés).
Publicaciones con una valoración positiva (votos) o sin votos
No cuentan las publicaciones con la etiqueta Feedback sobre la Comunidad de Desarrolladores.
Hay un retardo de 3 días entre la publicación de la traducción y la concesión de la insignia.
Advanced Translator
Conseguida por 5 traducciones
Insignia del 3er nivel (Specialist)
Bronze Translator
Conseguida por 15 traducciones
Insignia del 4º nivel (Expert)
Silver Translator
Conseguida por 25 traducciones
Insignia del 5º nivel (Ambassador)
Gold Translator
Conseguida por 50 traducciones
Insignia del 6º nivel (VIP)
¿Cómo puedes saber en qué nivel de Global Masters estás y las insignias que tienes? Sigue estos sencillos pasos:
1. En la página de inicio de Global Masters, haz clic en la foto de tu perfil, en la parte superior derecha > después, haz clic en tu nombre
2. Ahí ya puedes ver en qué nivel estás, las insignias que has ganado y lo que te falta para pasar al siguiente nivel
2. Si haces clic en "See available badges" verás todas las insignias y niveles del programa
¿Quieres saber más sobre Global Masters?
Echa un vistazo a estas otras publicaciones:
Cómo unirse a Global Masters
Descripción de los niveles de Global Masters
Cómo conseguir puntos en Global Masters
Si aún no perteneces al Programa de Fidelización de InterSystems, ¡te puedes dar de alta ahora mismo!
Si tienes alguna duda, puedes dejarnos un comentario en esta publicación y te responderemos al momento.
Artículo
Alberto Fuentes · 29 jun, 2022
¡Hola Comunidad!
Me gustaría anunciaros brevemente tres nuevos paquetes, disponibles en Open Exchange / a través de ZPM, que pueden realmente ayudaros a acelerar el desarrollo en IRIS de aplicaciones full-stack modernas. Todo esto se anunció la semana pasada en una sesión del Global Summit, pero muchos no pudisteis asistir. Además, me acabo de enterar de que justo ahora está en marcha un concurso de desarrollo de aplicaciones full-stack!
En el corazón de todo esto está isc.rest: una continuación de apps-rest con un uso más amplio dentro de InterSystems y varias nuevas funcionalidades geniales - especialmente, la generación de especificaciones OpenAPI. isc.rest hace posible el acceso REST sencillo a tus datos: extiende una clase, sobreescribe un parámetro y especifica seguridad para el nuevo recurso REST que estás creando. Esto está respaldado por isc.json, un subproyecto autorizado del paquete IRIS %JSON, desarrollado para ayudar a potenciar el soporte a JSON en IRIS a través del feedback de la Comunidad.
Del lado de la interfaz de usuario (UI), isc.ipm.js adapta el gestor de paquetes de IRIS para simplificar la creación y desarrollo de modernas interfaces de usuario, junto con código del lado del servidor, incluyendo la generación de código cliente basada en las especificaciones de la Open API de isc.rest y una nueva fase "generate" del ciclo de vida del gestor de paquetes. Con isc.ipm.js puedes publicar tu paquete en un registro privado (usando zpm-registry) y distribuir tu código del lado del servidor y crear artefactos UI sin necesidad de reconstruir el cliente (o hacer commit de tus artefactos construidos al sistema de control de código).
Por último, isc.perf.ui sirve como una demo para todo lo anterior - y una demo práctica, empleando el monitor de línea por línea (^%SYS.MONLBL) y ofreciendo acceso a resultados a través de una sencilla UI Angular.
Publicaré más artículos sobre esto en las próximas semanas - ¡estad atentos!
Artículo
Eduardo Anglada · 29 dic, 2021
Hablando con mi amigo @Renato.Banzai, especialista en Machine Learning, me comentó uno de los mayores retos a los que se enfrentan las empresas hoy en día: implementar el Machine Learning (ML) o la Inteligencia Artificial (IA) en entornos reales.
InterSystems IRIS ofrece IntegratedML. IntegratedML es una excelente funcionalidad para formarse, probar e implementar modelos de ML/IA.
La parte más difícil al crear ML/IA es el tratamiento de los datos, su limpieza, hacerlos fiables.
¡Y ahí es donde podemos sacar ventaja del potente estándar FHIR!
La idea del proyecto muestra cómo podemos crear/entrenar/validar modelos de ML/IA con FHIR y utilizarlos con datos de diferentes fuentes.
Creemos que este proyecto tiene un gran potencial y se pueden explorar varias ideas:
Reutilizar/extender las transformaciones DTL en otras bases de datos FHIR para modelos de ML a medida
Usar transformaciones DTL para normalizar mensajes FHIR y publicar modelos de ML como servicios
Crear un tipo de modelos + repositorio de reglas de transformación para usar dentro de cualquier conjunto de datos FHIR
Explorando nuevas posibilidades con este proyecto, podemos imaginar datos de diferentes fuentes.
En la imagen arribla, el Recurso FHIR (FHIR Resource), consumiendo la API REST, puede ser usado con una FHIRaaS.
Y no solo usando FHIRaaS en AWS, sino que también podemos usar el nuevo servicio HealthShare Message Transformation Services, que automatiza la conversión de HL7v2 a FHIR® para ingresar datos en Amazon HealthLake, donde puedes extraer más valor de tus datos.
Con estas pequeñas demostraciones, veo que estos recursos se pueden utilizar muy bien en escenarios más grandes, permitiendo y ofreciendo implementaciones más sencillas en producción en entornos realmente innovadores, como AWS Healthlake. ¿Por qué no?! 😃
Artículo
Alberto Fuentes · 16 ene, 2023
cAdvisor (abreviatura de contenedor Advisor) analiza y muestra el uso de recursos y los datos de rendimiento desde los contenedores en ejecución. cAdvisor ya viene preparado para publicar métricas en formato Prometheus.
https://prometheus.io/docs/guides/cadvisor/
Prometheus está integrado en SAM. Esto permite aprovechar las métricas de cAdvisor y mostrarlas a través de Prometheus y Grafana.
Como cAdvisor escucha en el puerto 8080, que entra en conflicto con el puerto de Nginx, puedes cambiar el puerto Nginx para solucionarlo:
Pasos para realizar la configuración:
1. Cambia el puerto nginx.
modifica nghix.conf:
server { listen 9991;
Esto te permite acceder al IU de cAdvisor a través de http://server:8080/, que incluye muchos cuadros de mando (dashboards) de ejemplo.
2. Configura docker-compose para añadir el contenedor cAdvisor:
en docker-compose.yml, añade lo siguiente:
cadvisor: image: google/cadvisor:latest ports: - 8080:8080 volumes: - /:/rootfs:ro - /var/run:/var/run:rw - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro
3. Configura prometheus para añadir un trabajo para cAdvisor:
modifica isc_prometheus.yml y añade:
- job_name: cadvisor scrape_interval: 5s static_configs: - labels: cluster: "1" group: node targets: - cadvisor:8080
¡Ya está! Para asegurarse de que prometheus está cogiendo las métricas de cAdvisor, ve al IU de prometheus http://server:9090/. En Status->Targets, deberías ver el endpoint y el estado de cAdvisor.
Puedes descargar unos excelentes cuadros de mando (dashboards) predefinidos con métricas de cAdvisor. Solo necesitas añadir el parámetro del cluster en cada consulta.
Este artículo está etiquetado como "Mejores prácticas" ("Best practices").
Los artículos con la etiqueta "Mejores prácticas" incluyen recomendaciones sobre cómo desarrollar, probar, implementar y administrar mejor las soluciones de InterSystems.
Artículo
Evgeny Shvarov · 18 jul, 2022
¡Hola Comunidad!
@Joan.Pérez publicó una reseña en la que comentó que no está muy claro qué aplicaciones están disponibles para InterSystems Package Manager. ¡Gracias por tu pregunta, Joan! De hecho, la respuesta merece una publicación.
Existen al menos dos formas de conocer las aplicaciones con ZPM:
1. Ejecutar el comando find en zpm:
IRISAPP>zpm
=============================================================================
|| Welcome to the Package Manager Shell (ZPM). ||
|| Enter q/quit to exit the shell. Enter ?/help to view available commands ||
=============================================================================
zpm:IRISAPP>find
registry https://pm.community.intersystems.com:
analytics-okr 1.0.0
analyzethis 1.2.4
aoc-2021-uvg 0.0.2
aoc2021-rcc 0.0.2
appmsw-dbdeploy 1.0.3
appmsw-docbook 1.0.5
appmsw-forbid-old-passwd 1.0.4
....
O find -d para que aparezca el listado con sus descripciones:
zpm:IRISAPP>find -d
registry https://pm.community.intersystems.com:
analytics-okr 1.0.0
analyzethis 1.2.4 Description: Module that helps to
generate cubes, pivots and
dashboards vs IRIS data
aoc-2021-uvg 0.0.2 Description: Advent of code 2021 in
COS classes
aoc2021-rcc 0.0.2 Description: AoC-2021 full Embedded
Python demo
appmsw-dbdeploy 1.0.3 Description: An example of deploying
solutions with prepared databases,
even without source code.
appmsw-docbook 1.0.5 Description: Importing docbook
...
2. La segunda forma es filtrar las aplicaciones con ZPM en Open Exchange:
¿Compartís vuestra forma de conocer los paquetes públicos?
Esto está relacionado con repositorios públicos. Por supuesto, hay muchos repositorios privados que no sabemos lo que hay allí. ¿Vosostros cómo mostráis los paquetes?
Pregunta
Jose-Tomas Salvador · 21 oct, 2022
Buenos días, tardes, noches,...
Una pequeña reflexión/pregunta para hoy... es una realidad que las nuevas versiones de IRIS for Health son cada vez más potentes en cuanto a capacidades FHIR. Permiten consumir recursos FHIR con extrema facilidad, podemos crear conexiones con end-points de servidores FHIR externos muy facilmente y hacer que IRIS actúe de passthrough o que consuma esos recursos... o, más aún, podemos definir y poner en funcionamiento un repositorio FHIR, literalmente, en menos de 5 minutos.
Sin embargo, hay una cosa que hecho en falta en proyectos de tipo FHIR Façade, cuando tenemos que implementar una capa FHIR sobre un sistema que "no habla" FHIR. Se trata de la posiblidad de tener ayuda en nuestro IDE (Studio o VS Code) a la hora de codificar la lógica que crearía el o los objetos dinámicos (%DynamicObject) que representan los recursos FHIR que queremos definir...
Creo que sería de mucha ayuda disponer de estructuras/objetos que representasen los recursos de la versión FHIR con la que estemos trabajando, de modo que el intellisense de nuestro Studio o VS Code nos pudiera ofrecer ayuda en cuando a propiedades, objetos referenciados, etc,... y, no sólo eso, sino que también pudieramos utilizar esos objetos como base a la hora de definir nuestras transformaciones en el editor DTL, para crear recursos/objetos FHIR a partir de otros datos persistentes.
No sé si es algo que sólo yo hecho en falta o es más comun, por eso quería lanzar la pregunta a la comunidad. ¿Os habéis encontrado con esta situación? ¿Pensáis que es una funcionalidad interesante? ¿Tenéis algún workaround que queráis compartir?
Lo planteé en su día en el Portal de Ideas/Sugerencias que InterSystems pone a disposición de la comunidad. Aquí está la entrada por si queréis votar por ella, o aportar ideas/workarounds, etc...
Bueno, pues ahí queda la reflexión/pregunta.
¡¡Happy Coding!!
Artículo
Esther Sanchez · 8 jun, 2023
¡Hola Comunidad!
Hemos llegado al final del #GlobalSummit23 - ¡último día! Y es nuestro día - el día del desarrollador. Todas las ponencias estuvieron dedicadas a los desarrolladores, su crecimiento, aspiraciones e innovaciones.
Durante su presentación, @Dean.Andrews2971 habló sobre la Comunidad de Desarrolladores, entre otras cosas. Podéis ver la ponencia en Youtube tal como la grabé yo, o esperar a que publiquen la grabación oficial:
Después de comer, todos los moderadores de la Comunidad que habían ido al Global Summit se reunieron en una sesión llamada "Cómo aprovechar al máximo la Comunidad de Desarrolladores de InterSystems". Este año había mucha más gente que el año pasado!
@Dean.Andrews2971 mostró las novedades y funcionalidades de la Comunidad, Global Masters, Open Exchange y el Portal de Ideas; y cómo aprovecharlos.
Y después hubo una sesión abierta para comentar lo que cualquiera quisiera preguntar 😊
@Dmitry.Maslennikov, de la Comunidad de Desarrolladores en inglés.
@José.Pereira, de la Comunidad de Desarrolladores en portugués.
@Muhammad.Waseem, de la Comunidad de Desarrolladores en inglés.
@Francisco.López1549, de la Comunidad de Desarrolladores en español.
@Lorenzo Scalese, de la Comunidad de Desarrolladores en francés.
@Scott Roth, de la Comunidad de Desarrolladores en inglés.
Y la foto final con todos los moderadores que asistieron al Global Summit. De izquierda a derecha: @José.Pereira, @Muhammad.Waseem, @Djeniffer.Greffin7753, @Scott.Roth, @Dean.Andrews2971, @John.Murray, @Irène.Mykhailova, @Lorenzo.Scalese, @Francisco.López1549.
¡Qué grupo de personas tan agradable!
Espero que todos disfrutaran de esos 45 minutos.
Tras la sesión, ya era casi la hora del último helado y café! Pero antes eché un vistazo a @Guillaume.Rongier7183, que estaba terminando su ponencia sobre su tema favorito: Python.
Me junté con @Dmitry.Maslennikov, @Murray.Oldfield y nuestro nuevo miembro de la Comunidad - @Vladimir.Babarykin.
Y literalmente atrapé a @Vita.Tsareva, de Caelestinus, tras el adiós final.
Y esto ha sido todo. Espero que os hayan gustado mis crónicas de cómo fue mi Global Summit.
Podéis compartir vuestros comentarios en esta publicación. ¿Y dónde creéis que será el Global Summit de 2024? Ese es un tema interesante 😀
¡Allí nos veremos!
Artículo
Estevan Martinez · 29 ago, 2019
¡Hola a tod@s de nuevo!En este tercer artículo (consulte la Parte 1 y la Parte 2) continúo con la presentación de la estructura interna de las bases de datos en Caché. Esta vez, les contaré algunas cosas interesantes y les explicaré cómo mi proyecto sobre el Explorador de bloques en Caché puede ayudarles a hacer que su trabajo sea más productivo.Creo que muchos de ustedes reconocerán lo que se muestra en la imagen (sobre la que se puede hacer clic). Cuando necesité visualizar la fragmentación de los globales, lo primero que pasó por mi mente fueron varias herramientas para desfragmentar el disco. Y, tengo la esperanza, de que conseguí elaborar un producto que es tan útil como dichas herramientas para hacerlo.En esta herramienta se muestra un diagrama de bloques. Donde cada cuadro representa un bloque, y su color corresponde a un global determinado, el cual se muestra mediante una lista en la sección de leyendas. Cada uno de los bloques, por sí mismo, también muestra que tan saturado de datos está. Esto les ayudaría a calcular rápidamente la capacidad de toda la base de datos con tan solo echar un vistazo en el diagrama. La visualización del global y niveles del diagrama de bloques aún no se han implementado, al igual que todos los bloques vacíos, por lo que estos se mostrarán en color blanco.Puede seleccionar una base de datos y el diagrama de bloques comenzará a cargarlos inmediatamente. La información no se carga de manera consecutiva, sino que lo hace de acuerdo al orden que tengan los bloques en el árbol de bloques, de modo que el proceso puede verse muy similar al que se muestra en la siguiente imagen.Continuaremos trabajando con la base de datos que utilizamos en el artículo anterior. Eliminé todos los globales, ya que no los necesitaremos. También generé nuevos datos mediante el paquete de la clase Sample, la cual se encuentra en la base de datos SAMPLES. Para hacerlo, configuré el mapeo de paquetes con mi namespace llamado HAB.Después, ejecuté un comando para generar datos.
do ##class(Sample.Utils).Generate(20000)
En nuestro mapa, obtuve el siguiente resultado:
Observe que los bloques no comienzan a llenarse desde el inicio del archivo. Comienzan a llenarse a partir del bloque 16 y vemos los bloques puntero en el nivel superior desde el bloque 50, en los bloques de datos. Tanto el 16 como el 50 son valores predeterminados pero, si es necesario, pueden modificarse. El inicio del bloque puntero se define en la propiedad NewGlobalPointerBlock de la clase SYS.Database, en esta se establece el valor predeterminado para los nuevos globales. Para los globales que ya existen, esto se puede modificar desde la clase %Library.GlobalEdit mediante la propiedad PointerBlock. El bloque que iniciará la secuencia de bloques de datos se especifica en la propiedad NewGlobalGrowthBlock de la clase SYS.Database. La propiedad GrowthBlock de la clase %Library.GlobalEdit hace lo mismo para los globales individuales. La modificación de estas propiedades únicamente tiene sentido para aquellos globales que todavía no contienen datos, ya que estos cambios no tienen efecto sobre la posición actual del bloque puntero que se encuentra en el nivel superior o de los bloques de datos.
Aquí podemos ver que el global ^Sample.PersonD cuenta con 989 bloques y está lleno en un 83%, seguido por el global ^Sample.PersonI que tiene 573 bloques (y está lleno en un 70% de su capacidad). Podemos escoger cualquiera de los globales para ver los bloques que están asignados para él. Y si seleccionamos el global ^Sample.PersonI, veremos que algunos de sus bloques están casi vacíos. También podemos ver que los bloques que pertenecen a estos dos globales están mezclados. Pero existe una razón para esto. Cuando se crean nuevos objetos, ambos globales se llenan: uno con los datos y el otro con los índices para la tabla Sample.Person.
Ahora que tenemos algunos datos para hacer una prueba, podemos aprovechar las funciones de administración de la base de datos que ofrece Caché y ver el resultado. Para comenzar, ajustemos un poco nuestros datos para crear una ilusión de actividad, en la que se puedan añadir y eliminar datos. Ejecutaremos un código que eliminará algunos datos de manera aleatoria.
set id=""
set first=$order(^Sample.PersonD(""),1)
set last=$order(^Sample.PersonD(""),-1)
for id=first:$random(5)+1:last {
do ##class(Sample.Person).%DeleteId(id)
}
Cuando ejecute este código, verá el resultado que se muestra a continuación. Tenemos algunos bloques vacíos, mientras que otros están llenos entre un 64% y un 67% de su capacidad.
Podemos utilizar la herramienta ^DATABASE desde el namespace %SYS para trabajar con nuestra base de datos. Utilizaremos algunas de sus funciones.
En primer lugar, ya que apenas llenamos los bloques, vamos a comprimir todos los globales de la base de datos y veamos lo que ocurre.
Como puede ver, la compresión nos permitió acercarnos, tanto como fue posible, al valor que necesitábamos del 90% de la capacidad. Y como resultado, los bloques que antes estuvieron vacíos ahora están llenos de los datos que se reubicaron desde los otros bloques. Los globales de la base de datos pueden comprimirse utilizando la herramienta ^DATABASE (función 7) o mediante el siguiente comando con la ruta hacia la base de datos que se aprobó como el primer parámetro:
do ##class(SYS.Database).CompactDatabase("c:\intersystems\ensemble\mgr\habr\")
También podemos mover todos los bloques vacíos hacia el final de la base de datos. Esto puede ser necesario, por ejemplo, cuando elimine una gran cantidad de datos y posteriormente desee compactar la base de datos. Para demostrar esto, repetiremos la eliminación datos desde la base de datos con la que hicimos nuestra prueba.
set gn=$name(^Sample.PersonD)
set first=$order(@gn@(""),1)
set last=$order(@gn@(""),-1)
for i=1:1:10 {
set id=$random(last)+first
write !,id
set count=0
for {
set id=$order(@gn@(id))
quit:id=""
do ##class(Sample.Person).%DeleteId(id)
quit:$increment(count)>1000
}
}
Esto es lo que obtuve después de la eliminación de datos.
Aún podemos ver algunos bloques vacíos aquí. Caché le permite mover estos bloques vacíos al final del archivo de la base de datos y después compactarlos. Para mover los bloques vacíos, utilizaremos el método FileCompact desde la clase SYS.Database, que se encuentra en el namespace del sistema o podemos recurrir a la herramienta ^DATABASE (función 13). En este método se aceptan tres parámetros: la ruta hacia la base de datos, la cantidad de espacio libre que deseamos obtener al final del archivo (0 como valor predeterminado), y el parámetro de retorno (la cantidad de espacio libre resultante).
do ##class(SYS.Database).FileCompact("c:\intersystems\ensemble\mgr\habr\",999)
Y esto es lo que obtenemos: no hay ningún bloque vacío. Los únicos bloques vacíos que aparecen al principio no cuentan, ya que se encuentran allí debido a la configuración (el lugar donde comienza el puntero del nivel superior más alto y los bloques de datos).
Desfragmentación
Ahora podemos realizar la desfragmentación de nuestros globales. En este proceso se reordenarán los bloques de cada global con una distribución diferente. Para la desfragmentación puede requerirse que haya algo de espacio libre al final del archivo de la base de datos, de modo que este espacio puede añadirse si la situación así lo requiere. El proceso puede iniciarse mediante la función 14 de la herramienta ^DATABASE o utilizando el siguiente comando:
d ##class(SYS.Database).Defragment("c:\intersystems\ensemble\mgr\habr\")
Liberación de espacio en disco
Ahora podemos ver nuestros globales alineados. Sin embargo, parece que la desfragmentación utilizó un poco más de espacio adicional en el archivo de la base de datos. Podemos liberar este espacio utilizando la función 12 de la herramienta ^DATABASE o mediante el siguiente comando:
d ##class(SYS.Database).ReturnUnusedSpace("c:\intersystems\ensemble\mgr\habr\")
Ahora, nuestra base de datos ocupa mucho menos espacio y solo queda 1 Mb de espacio libre en el archivo de la base de datos. La posibilidad de desfragmentar a los globales en una base de datos y administrar el espacio libre que tienen disponible al mover los bloques y crear espacio para liberar otros se introdujo recientemente. Antes de eso, cada vez que era necesario desfragmentar la base de datos y reducir el tamaño del archivo de la base de datos se tenía que utilizar la herramienta ^GBLOCKCOPY . Esta realizaba una copia "bloque por bloque" desde la base de datos de origen hacia otra que se hubiera creado recientemente, y permitía que el usuario seleccionara los globales específicos que se iban a transferir. La herramienta todavía está disponible.
Artículo
Ricardo Paiva · 9 abr, 2021
### Objetivo
Esta herramienta se usa para generar una Entrada/Salida (E/S) de lectura aleatoria desde dentro de la base de datos. La finalidad de esta herramienta es llevar la mayor cantidad de tareas posibles para conseguir las IOPS objetivo y asegurar que se mantienen tiempos de respuesta de disco aceptables. Los resultados recopilados de las pruebas de E/S variarán de configuración a configuración, de acuerdo con el subsistema de E/S. Antes de ejecutar estas pruebas, asegúrate de que el sistema operativo y la monitorización del nivel de almacenamiento estén configurados para capturar métricas de desempeño de E/S para su posterior análisis.
### Metodología
Empieza con una cantidad reducida de procesos y 10 000 iteraciones por proceso. Usa 100 000 iteraciones por proceso para matrices de almacenamiento basadas íntegramente en tecnología flash. A continuación, aumenta el número de procesos, por ejemplo, empieza con 10 trabajos y aumenta en 10, 20, 40, etc. Sigue ejecutando pruebas individuales hasta que el tiempo de respuesta esté por encima de 10 ms de forma constante, o las IOPS calculadas ya no aumenten de forma lineal.
Como guía, los siguientes tiempos de respuesta para lecturas aleatorias de bases de datos de 8KB y 64KB (sin cache) normalmente son aceptables para las matrices íntegramente flash:
* Promedio <= 2ms
* No debe exceder <= 5ms
La herramienta necesita una base de datos IRIS.DAT pre-expandida vacía, de un tamaño de al menos el doble del espacio de memoria en el servidor y de al menos cuatro veces el tamaño del la cache del controlador de almacenamiento. La base de datos debe ser mayor que la memoria, para asegurar que las lecturas no se guarden en la cache del sistema de archivos.
La herramienta usa el comando VIEW de ObjectScript, que lee bloques de bases de datos en memoria, así que si no estás logrando los resultados esperados, puede que todos los bloques de la base de datos ya estén en memoria.
### Especificaciones y objetivos
Completa la siguiente tabla con tus objetivos y especificaciones de entorno:
| Especificación | Ejemplo |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Almacenamiento | Especificación de la matriz de almacenamiento |
| Servidor físico | CPU, especificación de la memoria |
| Máquina virtual | Red Hat Enterprise Linux 7 24 vCPU, 40GB vRAM |
| Tamaño de la base de datos | 200GB |
| Memoria compartida | Memoria compartida asignada de 26,956MB usando Huge Pages: búferes globales de 24,000MB, búferes de rutina de 1,000MB |
| IOPS objetivo | 2,000 |
| Tiempo de respuesta objetivo | <=5ms |
### Instalación
Descarga la herramienta **PerfTools.RanRead.xml** de GitHub [aquí](https://github.com/intersystems/random-read-performance-tool).
Importa **PerfTools.RanRead.xml** en el namespace USER.
USER> do $system.OBJ.Load("/tmp/PerfTools.RanRead.xml","ckf")
Ejecuta el método Help para ver todos los puntos de acceso. Todos los comandos se ejecutan en %SYS.
USER> do ##class(PerfTools.RanRead).Help()
InterSystems Random Read IO Performance Tool
--------------------------------------------
do ##class(PerfTools.RanRead).Setup(Directory,DatabaseName,SizeGB,LogLevel)
- Creates database and namespace with the same name. The log level must be in the range of 0 to 3, where 0 is “none” and 3 is “verbose”.
do ##class(PerfTools.RanRead).Run(Directory,Processes,Iterations)
- Run the random read IO test.
do ##class(PerfTools.RanRead).Stop()
- Terminates all background jobs.
do ##class(PerfTools.RanRead).Reset()
- Deletes all random read history stored in ^PerfTools.RanRead*
do ##class(PerfTools.RanRead).Export(directory)
- Exports a summary of all random read test history to tab delimited text file.
### Configuración
Crea una base de datos vacía (preexpandida) llamada ZRANREAD de aproximadamente el doble de tamaño de la memoria del servidor físico a probar. Asegúrate de que la base de datos vacía tenga al menos cuatro veces el tamaño de la cache del controlador de almacenamiento. Para crear automáticamente un namespace y una base de datos, puedes hacerlo manualmente o usar el siguiente método.
USER> do ##class(PerfTools.RanRead).Setup("/usr/iris/db/zranread","ZRANREAD",100,1)
Creating 100GB database in /usr/iris/db/zranread/
Database created in /usr/iris/db/zranread/
Run %Installer Manifest...
2016-05-23 13:33:59 0 PerfTools.RanRead: Installation starting at 2016-05-23 13:33:59, LogLevel=1
2016-05-23 13:33:59 1 CreateDatabase: Creating database ZRANREAD in /usr/iris/db/zranread// with resource
2016-05-23 13:33:59 1 CreateNamespace: Creating namespace ZRANREAD using ZRANREAD/ZRANREAD
2016-05-23 13:33:59 1 ActivateConfiguration: Activating Configuration
2016-05-23 13:34:00 1 EnableEnsemble: Enabling ZRANREAD
2016-05-23 13:34:00 1 ActivateConfiguration: Activating Configuration
2016-05-23 13:34:00 0 PerfTools.RanRead: Installation succeeded at 2016-05-23 13:34:00
2016-05-23 13:34:00 0 %Installer: Elapsed time 1.066633s
Database /usr/iris/db/zranread/ ready for testing.
do ##class(PerfTools.RanRead).Run(directory,processes,iterations) e.g.
do ##class(PerfTools.RanRead).Run("/usr/iris/db/zranread/",1,10000)
### Ejecución
Ejecuta el método Run aumentando la cantidad de procesos y tomando nota, cada vez, del tiempo de respuesta.
Si las pruebas son demasiado rápidas o los resultados no son los esperados, aumenta entonces el número de iteraciones a 10 000.
USER> do ##class(PerfTools.RanRead).Run("/usr/iris/db/zranread",20,10000)
InterSystems Random Read IO Performance Tool
--------------------------------------------
Starting 20 jobs in the background.
To terminate jobs run: do ##class(PerfTools.RanRead).Stop()
Waiting for jobs to finish.........................
Random read background jobs finished.
20 processes (1000 iterations) average response time = 7.18ms
Calculated IOPS = 2787
### Resultados
Los resultados para cada ejecución se guardan en USER en la tabla SQL PerfTools.RanRead. Ejecuta la siguiente consulta SQL para ver un resumen de resultados.
SELECT RunDate,RunTime,Database,Iterations,Processes,
{fn ROUND(AVG(ResponseTime),2)} As ResponseTime,
{fn ROUND(AVG(IOPS),0)} As IOPS
FROM PerfTools.RanRead
GROUP BY Batch
Para exportar el conjunto de resultados a un archivo de texto delimitado por tabulaciones, ejecuta lo siguiente:
USER> do ##class(PerfTools.RanRead).Export("/usr/iris/db/zranread/")
Exporting summary of all random read statistics to /usr/iris/db/zranread/PerfToolsRanRead_20160523-1408.txt
Done.
### Análisis
Abre en Excel el archivo de texto exportado. Luego, copia y pega los datos en la hoja de cálculo PerfToolsRandomRead\_Analysis\_Template.xlsx para hacer un gráfico.

La hoja de cálculo de muestra se puede descargar desde GitHub [aquí](https://github.com/intersystems/random-read-performance-tool).
### Limpieza
Cuando se terminen de ejecutar las pruebas, elimina el historial ejecutando:
%SYS> do ##class(PerfTools.RanRead).Reset()