<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonas Barros</title>
    <description>The latest articles on DEV Community by Jonas Barros (@jonasbarros).</description>
    <link>https://dev.to/jonasbarros</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F687775%2Fdeed8cd8-0269-4659-9e2f-14b5ad049fca.jpeg</url>
      <title>DEV Community: Jonas Barros</title>
      <link>https://dev.to/jonasbarros</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jonasbarros"/>
    <language>en</language>
    <item>
      <title>Change data capture com AWS RDS e PostgreSQL</title>
      <dc:creator>Jonas Barros</dc:creator>
      <pubDate>Wed, 08 Jan 2025 23:41:50 +0000</pubDate>
      <link>https://dev.to/jonasbarros/change-data-capture-com-aws-rds-e-postgresql-55en</link>
      <guid>https://dev.to/jonasbarros/change-data-capture-com-aws-rds-e-postgresql-55en</guid>
      <description>&lt;h3&gt;
  
  
  Visão geral
&lt;/h3&gt;

&lt;p&gt;Change Data Capture ou CDC é um método utilizado para extrair dados de uma base primária para uma outra base de destino utilizando algum conector para viabilizar essa comunicação&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbqgi4t6uwtcw6sh8hv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbqgi4t6uwtcw6sh8hv9.png" alt="image" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esse conector será ativado quando ocorrer um evento no qual alterará o estado da sua base de dados primária.&lt;/p&gt;

&lt;p&gt;Após a ocorrência deste evento, o conector será ativado recebendo os dados que foram alterados, com estes dados em mãos nós podemos enviá-los para outro ambiente, como por exemplo uma outra base de dados como um data lake.&lt;/p&gt;

&lt;p&gt;Existem diversas ferramentas que poderíamos escolher para desenvolvermos o nosso fluxo de &lt;em&gt;change data capture&lt;/em&gt;. O Dynamodb streams e AWS RDS com SQL Server são algumas ferramentas que possuem a funcionalidade de captura de eventos e migração de dados de forma nativa. Mas também podemos criar o nosso próprio &lt;em&gt;change data capture&lt;/em&gt; utilizando os triggers do PostgreSQL para capturar as mudanças de estados e enviá-las ao conector. &lt;/p&gt;

&lt;p&gt;Portanto ao decorrer deste artigo, irei mostrar como poderemos criar o nosso próprio fluxo de &lt;em&gt;change data capture&lt;/em&gt; utilizando o AWS RDS Aurora PostgreSQL. Criaremos os triggers para observarmos as mudanças de estado e utilizaremos a extensão aws_lambda para enviar os dados ao conector AWS lambda.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quando utilizar
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Se a base de dados primária for um data lake, podemos criar um fluxo para notificar o conector a cada novo item que for inserido na tabela. O conector poderá estruturar os dados e enviá-los ao data warehouse ou data lake.   &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O dynamodb possui um recurso chamado dynamodb streams, com ele nós conseguimos notificar outros serviços da AWS quando houver uma alteração de estado em algum item da tabela.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Podemos instalar a extensão aws_lambda no AWS RDS Aurora PostgreSQL para noticiar um conector como por exemplo um AWS lambda quando o estado de alguma tabela for alterada.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se tivermos implementando logs de auditoria, podemos aproveitar os recursos dos triggers do PostgreSQL para notificar os conectores quando houver um evento de inserção (insert), Atualização (update) ou Exclusão (delete) em uma ou múltiplas linhas da tabela. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quando não utilizar
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ao utilizar para construção de simples tarefas, como envio de e-mail ou para outras notificações a cada momento que o estado é atualizado. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quando a sua base de dados é muito pequena para se fazer essas transferências de dados, já que para construção deste fluxo acarretará em um aumento do custo mensal da conta AWS. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se você possuir uma base em uma versão do RDS que não é compatível com a extensão aws_lambda. Portando não será necessário migrar toda a sua base dados ao AWS RDS Aurora, é possível utilizar outras estratégias para criar um fluxo de dados CDC. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Criando um change data capture utilizando um cluster AWS RDS Aurora PostgreSQL
&lt;/h2&gt;

&lt;p&gt;Nos tópicos a seguir será apresentado como criar a infraestrutura inicial para um fluxo CDC no AWS Aurora PostgreSQL. Segue o link do repositório contendo todos os recursos necessários para iniciar a construção. &lt;/p&gt;

&lt;p&gt;Repositório: &lt;a href="https://github.com/JonasBarros1998/blog-devto/tree/main/change-data-capture-com-aws-rds-postgresql" rel="noopener noreferrer"&gt;Change data capture com AWS RDS Aurora PostgreSQL&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando e configurando o cluster AWS RDS PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Utilizando o módulo &lt;a href="https://registry.terraform.io/modules/terraform-aws-modules/rds-aurora/aws/latest" rel="noopener noreferrer"&gt;aurora_postgresql_v2&lt;/a&gt; nós podemos começar a criação de um &lt;a href="https://github.com/JonasBarros1998/blog-devto/blob/main/change-data-capture-com-aws-rds-postgresql/infra/main.tf#L57" rel="noopener noreferrer"&gt;cluster e uma instância do aurora PostgreSQL&lt;/a&gt;. &lt;br&gt;
Para que não haja custos elevados, sua configuração foi a mais básica possível, evitando adicionar outros recursos como escalabilidade e segurança no cluster RDS. &lt;/p&gt;

&lt;p&gt;Como nós criamos o cluster dentro de uma VPC, precisaríamos adicionar novos recursos para permitir a conexão entre máquina local e instância RDS. Um exemplo muito comum é criar uma instância EC2 que irá fazer a ponte e permitir a conexão entre máquina local e instância RDS. Porém fazer esse processo também envolve custos, &lt;br&gt;
portanto para que não tenhamos custos elevados enquanto estamos estudando o CDC, nós criamos a instância de forma &lt;a href="https://github.com/JonasBarros1998/blog-devto/blob/main/change-data-capture-com-aws-rds-postgresql/infra/main.tf#L79" rel="noopener noreferrer"&gt;pública&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;vpc_id&lt;/span&gt;                 &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vpc-0000000"&lt;/span&gt; &lt;span class="c1"&gt;# adicione o ID VPC da sua conta AWS &lt;/span&gt;
&lt;span class="nx"&gt;db_subnet_group_name&lt;/span&gt;   &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"default-vpc-0000"&lt;/span&gt; &lt;span class="c1"&gt;# adicione a subnet da conta AWS&lt;/span&gt;
&lt;span class="nx"&gt;security_group_name&lt;/span&gt;    &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"security"&lt;/span&gt; &lt;span class="c1"&gt;# adicione o security group name da conta AWS&lt;/span&gt;
&lt;span class="nx"&gt;publicly_accessible&lt;/span&gt;    &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# acesso público&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para realizar a conexão entre máquina local e cluster, podemos utilizar a porta 5432. &lt;/p&gt;

&lt;p&gt;Para que a conexão entre lambda e cluster ocorra com sucesso, precisamos adicionar regras de entrada e saída. Dentro destas regras, adicionamos um range com IP padrão apenas para fins de demonstração, mas em um ambiente produtivo configure corretamente o range de IP no qual o cluster aceitará receber conexões. &lt;/p&gt;

&lt;p&gt;A senha que precisamos para se conectar ao banco, é gerada automaticamente e adicionada no &lt;strong&gt;secret manager&lt;/strong&gt;. Portanto, &lt;br&gt;
para fazer a conexão com o cluster, acesse o secret manager no console AWS e copie a senha armazenada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;security_group_rules&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ex1_ingress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"5432"&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"5432"&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ingress"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ex2_ingress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"443"&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"443"&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ingress"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ex3_egress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"443"&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"443"&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"egress"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ex4_egress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"5432"&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"5432"&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"egress"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurando o IAM
&lt;/h3&gt;

&lt;p&gt;Como vimos no tópico anterior, foi preciso adicionar uma regra para aceitar conexões na porta 443 entre cluster e lambda. &lt;br&gt;
Mas não é só isso, precisamos também configurar políticas e roles para que a conexão entre os dois serviços seja realizada com sucesso. &lt;/p&gt;

&lt;p&gt;Criamos uma role do tipo Principal. Só com ela conseguiremos gerar credenciais temporárias para possibilitar a chamada da base de dados para a lambda&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-document-role-cluster-rds"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;

    &lt;span class="nx"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Service"&lt;/span&gt;
      &lt;span class="nx"&gt;identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"rds.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-role-cluster-rds"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-role"&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-document-role-cluster-rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida criamos uma política com uma ação de &lt;code&gt;lambda:InvokeFunction&lt;/code&gt;, o objetivo é dizer ao cluster que ele está habilitado a fazer chamadas a nossa função lambda, que criaremos logo em seguida. &lt;/p&gt;

&lt;p&gt;Com os recursos criados, agora só precisamos adicionar a role dentro do módulo postgreSQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-ducument-policy-cluster-rds"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ChangeDataCapturePolicy"&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"arn:aws:lambda:us-east-1:AWS_ACCOUNT_ID:function:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# anexamos a policy que criamos acima, dentro da nossa role&lt;/span&gt;
&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-role-attachment-cluster-rds"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-policy-cluster-rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-role-cluster-rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# dentro do modulo postgreSQL, adicionamos a role que criamos anteriormente&lt;/span&gt;
&lt;span class="nx"&gt;iam_roles&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;role_arn&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-role-cluster-rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
      &lt;span class="nx"&gt;feature_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Lambda"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Criando a função lambda
&lt;/h3&gt;

&lt;p&gt;Agora que terminamos a configuração do módulo postgresql e toda a estrutura de comunicação com outros serviços, precisamos criar e configurar a nossa lambda. &lt;/p&gt;

&lt;p&gt;Precisei criar uma nova &lt;strong&gt;&lt;em&gt;role do tipo Principal&lt;/em&gt;&lt;/strong&gt; para geração de credenciais temporárias. Esse é o processo padrão para criação de qualquer lambda&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-document-lambda-role"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Service"&lt;/span&gt;
      &lt;span class="nx"&gt;identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lambda.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-role-lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-lambda-document"&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-document-lambda-role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida, precisamos criar as políticas de acesso e a criação do recurso do &lt;strong&gt;&lt;em&gt;cloud watch&lt;/em&gt;&lt;/strong&gt;. Sem eles a lambda não conseguiremos observar o resultado da integração entre banco e lambda.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-lambda-policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda_logging"&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IAM policy for logging from a lambda"&lt;/span&gt;
  &lt;span class="nx"&gt;policy&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-ducument-policy-cloud-watch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-policy-attachment-lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-lambda-policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-role-lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_cloudwatch_log_group"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-cloudwatch"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/aws/lambda/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;retention_in_days&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida precisaremos dizer ao terraform qual é o arquivo que será inserido na lambda. Para isso criei um recurso que me diz qual o caminho para o arquivo ZIP, no qual deverá conter todo código fonte que utilizaremos.&lt;br&gt;
&lt;a href="https://github.com/JonasBarros1998/blog-devto/tree/main/change-data-capture-com-aws-rds-postgresql/src" rel="noopener noreferrer"&gt;Segue o repositório contendo o código fonte desenvolvido em Javascript&lt;/a&gt;. Desenvolvemos algo bem simples, apenas enviamos ao CloudWatch o que a lambda está recebendo ao ser chamada pelo banco de dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"archive_file"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-archive-file"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"zip"&lt;/span&gt;
  &lt;span class="nx"&gt;source_dir&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../src"&lt;/span&gt;
  &lt;span class="nx"&gt;output_path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-function-payload.zip"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-function"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;filename&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"change-data-capture-function-payload.zip"&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_name&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-role-lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"main.handler"&lt;/span&gt;
  &lt;span class="nx"&gt;source_code_hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;archive_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-archive-file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output_base64sha256&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nodejs20.x"&lt;/span&gt;
  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
    &lt;span class="nx"&gt;aws_iam_role_policy_attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-policy-attachment-lambda&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;aws_cloudwatch_log_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;change-data-capture-cloudwatch&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conectando o AWS RDS com a função lambda
&lt;/h2&gt;

&lt;p&gt;Antes de fazer os passos abaixo, certifique que os recursos foram criados corretamente quando rodou o comando terraform apply. Na AWS, acesse o secret manager e identifique a senha que foi criada quando o terraform foi executado. Copie e deixe-a separada já que iremos utilizá-la para se conectar com o banco.&lt;br&gt;
A senha mudará a cada momento em que você fazer o destroy da infra e recriá-la novamente. &lt;/p&gt;
&lt;h3&gt;
  
  
  Conectando com o banco de dados
&lt;/h3&gt;

&lt;p&gt;Na AWS acesse o RDS e identifique o cluster que foi criado. Ao selecionar o cluster, pegue a string de conexão, pois ela será necessária para fazermos a conexão entre a máquina local com o nosso banco de dados. A string de conexão deverá ter o seguinte formato:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{nome-do-cluster}.{numero-identificador}.{regiao}.rds.amazonaws.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Para fazer a conexão com o banco, utilize o seguinte comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psql -h {nome-do-cluster}.{identificador-unico}.{regiao}.rds.amazonaws.com -U cdcStoreDevTo -p 5432 -d cdcstore&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-h = host de conexão&lt;/code&gt;&lt;br&gt;
&lt;code&gt;-U = nome do usuário&lt;/code&gt;&lt;br&gt;
&lt;code&gt;-p = porta de conexão com o banco&lt;/code&gt;&lt;br&gt;
&lt;code&gt;-d = nome da database&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ao fazer o comando acima, vai aparecer no terminal um prompt para digitar a senha, portanto utilize a senha que foi criada e armazenada dentro do secret manager.&lt;br&gt;
Se a conexão for realizada com sucesso, você estará neste momento dentro da instância cdcstore&lt;/p&gt;
&lt;h3&gt;
  
  
  Instalando a extensão aws_lambda
&lt;/h3&gt;

&lt;p&gt;Após realizar a conexão com a instância, instale a extensão &lt;code&gt;aws_lambda&lt;/code&gt;. Mas para que seja possível fazer a chamada, precisamos também instalar a extensão &lt;code&gt;aws_commons&lt;/code&gt;. &lt;br&gt;
Ao inserir o comando abaixo, será instalada ambas as extensões que precisaremos para enviamos dados ao aws lambda.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;aws_lambda&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Mas o que são extensões no postgreSQL?
&lt;/h4&gt;

&lt;p&gt;A extensão é uma funcionalidade que você pode criar para fazer alguns trabalhos extras. Uma extensão bastante famosa no postgreSQL é o hstore, com ela nós podemos armazenar um conjunto de chave/valor em um único registro. Veja o exemplo abaixo, nós utilizamos a extensão como um tipo para o campo &lt;code&gt;products&lt;/code&gt;, e adicionamos os dados chave/valor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;hstore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="n"&gt;hstore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a=&amp;gt;b, c=&amp;gt;d'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;--consulta pelo item a&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- consulta pelo item b&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;aws_lambda&lt;/code&gt; também é uma extensão, como dizemos anteriormente, as extensões vão fazer um trabalho extra, ou aprimorar alguma funcionalidade como vimos com hstore.&lt;br&gt;
Veja que com o hstore é possível utilizar uma chave para consultar um único item ou um conjunto deles, dependendo dos valores que foram adicionados.&lt;/p&gt;

&lt;p&gt;Também é possível criar as nossas próprias extensões no postgreSQL. Para isso podemos criar um arquivo com extensão &lt;code&gt;nome_do_arquivo.sql&lt;/code&gt;, e adicionar todo o conteúdo da extensão dentro dele, e salvaremos esse arquivo dentro do diretório de instalação do postgreSQL na pasta /extension. Para encontrar o diretório de instalação consulte a documentação oficial do banco. Mas para sistemas operacionais baseados em linux, possivelmente irá encontrá-lo no seguinte caminho: &lt;code&gt;/usr/share/postgresql/{NUMERO_DA_VERSAO_DO_POSTGRESQL}/extension&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Após escrevemos a nossa extensão e inseri-la na pasta /extension, podemos instalar a extensão com o comando a seguir. Após instalada, poderá ser utilizada normalmente conforme você desenvolveu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;nome_extens&lt;/span&gt;&lt;span class="err"&gt;ã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Porém como estamos trabalhando com RDS, não será possível acessarmos o diretório de instalação do postgreSQL para criarmos as nossas extensões, logo teremos que utilizar uma nova abordagem chamada &lt;a href="https://docs.aws.amazon.com/pt_br/AmazonRDS/latest/UserGuide/PostgreSQL_trusted_language_extension-terminology.html" rel="noopener noreferrer"&gt;TLE - Trusted Language Extensions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Trusted Language Extension é um kit de desenvolvimento de código aberto utilizado para criar as nossas extensões de maneira segura. Como foi visto anteriormente, para instalar as extensões da maneira padrão, é necessário criar um script dentro da pasta /extension localizada no diretório de instalação do postgreSQL. Porém, por motivos de segurança o RDS não possibilita o acesso ao sistema de arquivos da máquina no qual está rodando a instância. E se desejarmos criar a nossa extensão para rodar dentro do RDS será necessário utilizar o kit de desenvolvimento TLE. &lt;/p&gt;

&lt;p&gt;Quando instalamos o TLE, temos disponíveis o que chamamos de linguagens seguras para desenvolver os nossos scripts, como por exemplo o PL/V8 no qual é uma biblioteca que fornece uma linguagem procedural para PostgreSQL que utiliza o V8 JavaScript Engine. Ao utilizá-la nós não conseguiremos acessar ou manipular quaisquer conteúdos dentro do sistema de arquivos da instância que roda o banco de dados. &lt;/p&gt;

&lt;p&gt;Na &lt;a href="https://www.postgresql.org/docs/current/plperl-trusted.html" rel="noopener noreferrer"&gt;documentação do PostgreSQL&lt;/a&gt; temos um exemplo no qual seremos barrados ao tentarmos criar um arquivo dentro do diretório /tmp. Este exemplo foi feito utilizando o PL/PERL no qual também é uma versão segura para criarmos as nossas extensões.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;badfunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
    &lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;tmpfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"/tmp/badfile"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;tmpfile&lt;/span&gt;
        &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;elog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qq&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;could&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="nv"&gt;"$tmpfile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;fh&lt;/span&gt; &lt;span class="nv"&gt;"Testing writing to a file&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;close&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;fh&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;elog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qq&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;could&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;close&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="nv"&gt;"$tmpfile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plperl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comando a seguir pressupõe que você já tenha criado um grupo de parâmetros para a sua instância, então você só precisará substituir a variável ADD_PARAMETER_GROUP_NAME pelo nome do grupo de parâmetros.  Ao final deste tópico terá um link para a documentação auxiliando na criação de um grupo de parâmetros para a instância que você está utilizando.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws rds modify-db-parameter-group &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--db-parameter-group-name&lt;/span&gt; ADD_PARAMETER_GROUP_NAME &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--parameters&lt;/span&gt;&lt;span class="s2"&gt;"ParameterName=shared_preload_libraries,ParameterValue=pg_tle,ApplyMethod=pending-reboot"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--region&lt;/span&gt; aws-region

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No comando acima nós estamos dizendo ao RDS para inicializar a extensão pg_tle na instância que está vinculada ao grupo de parâmetros. &lt;/p&gt;

&lt;p&gt;Se não houver nenhum erro ao executar o comando acima você deverá reiniciar a instância e logo em seguida baixar a extensão e executar o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;NOME_EXTENSAO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Segue alguns links úteis no qual explicam com mais detalhes sobre o TLE e nos ensinam a desenvolver nossas primeiras extensões. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aws/pg_tle/blob/main/docs/01_install.md#method-3-amazon-rds--amazon-aurora-only-use-parameter-groups" rel="noopener noreferrer"&gt;Como fazer a configurar e instalar uma extensão utilizando AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/pt_br/AmazonRDS/latest/UserGuide/PostgreSQL_trusted_language_extension-setting-up.html" rel="noopener noreferrer"&gt;Como fazer a instalação utilizando console AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aws/pg_tle/blob/main/docs/02_quickstart.md" rel="noopener noreferrer"&gt;Exemplos de extensões utilizando o SQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aws/pg_tle/blob/main/docs/07_plv8_examples.md" rel="noopener noreferrer"&gt;Exemplos de extensões utilizando o PL/V8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aws/pg_tle?tab=readme-ov-file#trusted-language-extensions-for-postgresql-pg_tle" rel="noopener noreferrer"&gt;Link da documentação completa no repositório oficial do pg_tle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/reference/rds/create-db-parameter-group.html" rel="noopener noreferrer"&gt;Criação de um grupo de parâmetros&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As extensões hstore e aws_lambda já vem pré-carregada dentro da instância aurora-postgresql portanto não será necessário realizar os descritos acima.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testando funcionalidade
&lt;/h2&gt;

&lt;p&gt;Vamos fazer um primeiro teste simples. Vamos utilizar a função &lt;code&gt;create_lambda_function_arn&lt;/code&gt; e passar o ARN da nossa lambda, em seguida passaremos uma string contendo apenas uma simples mensagem e converteremos esse valor para o tipo json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aws_commons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_lambda_function_arn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ARN FUNCAO LAMBDA'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'us-east-1'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'{"body": "Hello Word"}'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vá a AWS Console e observe os logs da função lambda no cloud watch. Veja que o resultado apresentado lá dentro condiz com &lt;br&gt;
o valor que passamos dentro da função &lt;code&gt;aws_lambda.invoke&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Testando funcionalidade de uma maneira mais complexa
&lt;/h2&gt;

&lt;p&gt;Vamos agora fazer algo mais complexo. Utilizaremos um trigger para ser acionado sempre quando houver uma inserção no banco de dados. Em seguida iremos notificar uma lambda que apenas escreverá no cloudWatch o valor que inserimos na função.&lt;/p&gt;
&lt;h3&gt;
  
  
  Criando uma tabela
&lt;/h3&gt;

&lt;p&gt;Primeiro vamos criar uma tabela para que no momento que inserirmos os dados o nosso trigger seja notificado&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;store_id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name_store&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    
  &lt;span class="n"&gt;segments&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Criando a estrutura do trigger
&lt;/h3&gt;

&lt;p&gt;Para se criar um trigger é muito simples então podemos seguir o que está descrito na &lt;a href="https://www.postgresql.org/docs/current/sql-createtrigger.html" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;integration_lambda_trigger&lt;/span&gt;
  &lt;span class="k"&gt;AFTER&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;
  &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;EACH&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt; 
  &lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;integration_lambda&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;-- integration_lambda_trigger: nome do trigger&lt;/span&gt;
&lt;span class="c1"&gt;-- integration_lambda(): nome da function&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida precisamos criar uma função que será chamada quando o trigger for acionado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;integration_lambda&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
  &lt;span class="k"&gt;DECLARE&lt;/span&gt;
    &lt;span class="n"&gt;json_text&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;BEGIN&lt;/span&gt; 
    &lt;span class="n"&gt;json_text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json_build_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'store_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name_store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'address'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'segments'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;PERFORM&lt;/span&gt; &lt;span class="n"&gt;aws_lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aws_commons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_lambda_function_arn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arn:aws:lambda:us-east-1:700552527916:function:change-data-capture'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'us-east-1'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;json_text&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Iniciamos a função com uma declaração de variável chamada json_text, nós utilizaremos para armazenar o valor de retorno da função chamada &lt;a href="https://www.postgresql.org/docs/current/functions-json.html" rel="noopener noreferrer"&gt;json_build_object()&lt;/a&gt;. Ela será a responsável por criar um JSON de acordo com os dados que inserimos na tabela &lt;code&gt;store&lt;/code&gt;. Para isso, teremos que estruturar a função da seguinte maneira. Devemos passar o nome da chave do json e logo em seguida o seu respectivo valor. &lt;br&gt;
Para pegarmos este valor podemos utilizar o operador &lt;code&gt;NEW&lt;/code&gt; composto pelo nome da coluna da tabela. &lt;code&gt;NEW.store_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;O próximo passo será fazer a chamada para a função Lambda com aws_lambda.invoke. Como primeiro parâmetro &lt;br&gt;
da função temos que passar o endereço da nossa lambda, ou seja o ARN e a região no qual a lambda foi criada. &lt;br&gt;
Já no segundo parâmetro, passamos a variável json_text no qual estará armazenado o JSON que enviaremos ao lambda. &lt;br&gt;
Observe também a expressão ::json. Somos obrigados a passar esse valor porque temos que fazer um cast para deixar explícito o tipo de dado que estamos enviando.&lt;/p&gt;

&lt;p&gt;Por fim, retornamos novamente o operador &lt;code&gt;NEW&lt;/code&gt; no final da função. &lt;/p&gt;

&lt;p&gt;Se observar no repositório, teremos um script SQL no qual temos todos esses passos sendo executados. Portanto vamos utilizá-lo enviando o comando no momento de fazer a conexão&lt;br&gt;
com o banco de dados. &lt;/p&gt;

&lt;p&gt;Mas também podemos utilizar o PgAdmim para executar todas as funcionalides incluidas no script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;nome-do-cluster&lt;span class="o"&gt;}&lt;/span&gt;.&lt;span class="o"&gt;{&lt;/span&gt;identificador-unico&lt;span class="o"&gt;}&lt;/span&gt;.&lt;span class="o"&gt;{&lt;/span&gt;regiao&lt;span class="o"&gt;}&lt;/span&gt;.rds.amazonaws.com &lt;span class="nt"&gt;-U&lt;/span&gt; cdcStoreDevTo &lt;span class="nt"&gt;-p&lt;/span&gt; 5432 &lt;span class="nt"&gt;-d&lt;/span&gt; cdcstore &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"localizacão do script .SQL"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Lembre-se que a senha para acesso ao banco se encontra no secret manager.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se você acabou de criar sua a sua instância e executou o script .sql, certamente você não terá nenhum recurso criado, logo aparecerá no seu terminal alguns logs de erro&lt;br&gt;
como esses: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;.../sql/script.sql:1: ERROR:  relation "store" does not exist&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.../sql/script.sql:2: ERROR:  could not find a function named "integration_lambda"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.../sql/script.sql:3: ERROR:  table "store" does not exist&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.../sql/script.sql:5: NOTICE:  extension "aws_lambda" already exists, skipping&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Mas não se preocupe, esses erros só ocorrerão quando você executar pela primeira vez, já que a todo o momento que executamos o script, adicionei algumas funcionalidades para remover todos os recursos criados anteriormente e recriá-los novamente. &lt;/p&gt;

&lt;p&gt;A seguir podemos executar alguns inserts para visualizar todos os recursos em funcionamento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'my store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'76 street'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'tecnology'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'my store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'76 street'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'tecnology'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se os comando retornarem sucesso após a sua execução, podemos olhar no CloudWatch e verificarmos o que a função lambda recebeu&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2024-12-18T20:01:12.517Z    INFO    {
  store_id: 1,
  name_store: 'my store',
  address: '76 street',
  segments: 'tecnology'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2024-12-18T20:01:19.034Z    INFO    {
  store_id: 2,
  name_store: 'my store',
  address: '76 street',
  segments: 'tecnology'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Portanto se você visualizou esse resultado, o fluxo funcionou como deveria. Como expliquei no inicio deste artigo, existem diversas maneiras no qual você utilizar para sair com o mesmo resultado. E também existem diversos casos de uso no qual fará sentido utilizar esses recursos, então analise com cuidado e opte ou não pela criação de um change data capture. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>rds</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Streaming de vídeos com AWS MediaConvert</title>
      <dc:creator>Jonas Barros</dc:creator>
      <pubDate>Sun, 04 Aug 2024 14:22:35 +0000</pubDate>
      <link>https://dev.to/jonasbarros/streaming-de-videos-com-aws-mediaconvert-1nob</link>
      <guid>https://dev.to/jonasbarros/streaming-de-videos-com-aws-mediaconvert-1nob</guid>
      <description>&lt;h3&gt;
  
  
  Prólogo
&lt;/h3&gt;

&lt;p&gt;Neste artigo, apresentarei como foi o processo de discovery e desenvolvimento do tech challenge que teve o seguinte tema: desenvolvimento de uma aplicação web de streaming de vídeos. Veremos quais ferramentas foram utilizadas, entenderemos como funciona um streaming de vídeo, aprenderemos sobre codecs, bitrate, segmentos, protocolos de vídeo, e, por fim, integraremos todas essas tecnologias utilizando o AWS MediaConvert.&lt;/p&gt;

&lt;p&gt;Esse tech challenge é um dos quatro trabalhos que tivemos que desenvolver durante o período da pós-graduação realizada na FIAP.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Ferramentas da AWS utilizadas para desenvolvimento do projeto
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AWS S3:  Para armazenar as mídias originais, e os pequenos pacotes de vídeo gerados após o processamento do MediaConvert.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS MediaConvert: Este é um serviço específico para processamento de vídeos. Com ele, é possível definir os protocolos de reprodução de vídeos, segmentos, bitrate, resolução, codecs e diversos outros parâmetros utilizados no desenvolvimento deste projeto.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS SQS: O serviço de mensageria da AWS foi utilizado para fazer a comunicação entre os dois microsserviços. O primeiro microsserviço é chamado de stream de vídeos, enquanto o segundo é chamado de pipeline de processamento de vídeos. Ao longo deste artigo, focaremos no desenvolvimento do microsserviço chamado pipeline de processamento de vídeos.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Arquitetura do projeto
&lt;/h3&gt;

&lt;p&gt;Abaixo estão os dois microsserviços que precisaram ser criados para o desenvolvimento do techchallange. O serviço que iremos aprofundar para melhor entendimento é a pipeline de processamento de vídeos. Dentro deste microsserviço nós temos a integração com o MediaConvert no qual será o foco principal deste artigo. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjwcv39d6xa4sjjo4vvr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjwcv39d6xa4sjjo4vvr.png" alt="Desenho arquitetural" width="800" height="742"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O primeiro microsserviço se chama stream de vídeos, será o responsável por enviar a mídia original ao AWS S3 e fazer as outras regras de negócio que eram requisitos obrigatórios do tech challange.&lt;/p&gt;

&lt;p&gt;Já o segundo microsserviço se chama pipeline de processamento de vídeos, em meu cenário ele é o responsável por fazer o processamento dos vídeos, por exemplo, separar a mídia bruta em pequenos pacotes para agilizar o tráfego do conteúdo na rede do usuário, definição dos codecs, resolução e bitrate. &lt;/p&gt;

&lt;p&gt;O MediaConvert no qual utilizamos, é uma ferramenta extremamente poderosa, com ela nós conseguimos fazer diversas configurações, inclusive fazer pequenas melhorias no vídeo. &lt;a href="https://docs.aws.amazon.com/mediaconvert/" rel="noopener noreferrer"&gt;Se não conhecer o MediaConvert&lt;/a&gt;, é importante entender um pouco sobre ele antes de continuar a leitura. Foi com ele que fizemos toda a configuração para processamento de vídeos. &lt;/p&gt;

&lt;p&gt;Observe também que entre os dois microsserviços existe o AWS SQS, como disse anteriormente ele é responsável por fazer a comunicação entre os serviços. No payload do SQS enviaremos o nome da mídia para que a pipeline de processamento de vídeo encontre-a no bucket e inicie os trabalhos de processamento.&lt;/p&gt;

&lt;p&gt;Existem outras ferramentas que poderíamos utilizar para construção de ambos os microsserviços. Uma das possibilidades seria a inclusão do AWS CloudFront para acelerar a entrega do conteúdo já processado em pequenos pacotes e armazenado no AWS S3. Mas todas essas mudanças e melhorias ficariam para uma segunda versão. A versão atual além de funcionar perfeitamente bem, fez com que o problema fosse resolvido de forma simples e o projeto tenha sido entregue dentro do prazo estipulado. &lt;/p&gt;

&lt;h3&gt;
  
  
  Quais tecnologias utilizamos para processamento de vídeo?
&lt;/h3&gt;

&lt;p&gt;Antes de iniciar qualquer desenvolvimento da pipeline de processamento de vídeo, precisaria estudar algumas ferramentas e configurações de edição de vídeo no qual eu não estava completamente familiarizado. Esta etapa foi importante para entender cada uma das ferramentas antes de partir para o desenvolvimento. &lt;/p&gt;

&lt;p&gt;Portanto Tive que responder algumas perguntas como por exemplo; o que seriam os protocolos HLS, IIS ou Dash ISO? O que significa bitrate? Baseado em meu cenário, qual o melhor codec de vídeo que eu poderia escolher? Me aprofundei para entender cada dos questionamentos e como isso poderia trabalhar de forma conjunta dentro de uma aplicação.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O que significam os protocolos HLS, IIS e Dash ISO?&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;HLS (HTTP Live Stream): Lançado em 2009 pela Apple, em princípio para funcionar apenas em seus Iphones porém logo se espalhou pelo mercado e atualmente é o protocolo mais utilizado para reprodução de vídeos. As principais características do HLS é a fragmentação da mídia original em pequenos pacotes com diversas resoluções para rápida distribuição de conteúdo pela rede do usuário. Para isso ele utiliza um formato chamado m3u8, no qual é um arquivo utilizado pelos players de reprodução de vídeo para que eles consigam saber a lista de reprodução para cada resolução.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;O protocolo HLS funciona da seguinte forma: Primeiro teremos que ter a mídia original, essa mídia deve estar com uma excelente qualidade de vídeo, a resolução ideal é estar acima do 1080p.&lt;br&gt;
A mídia será dividida em centenas ou milhares de pacotes (iremos definir isso dentro da aplicação), e cada uma deles terá  uma resolução específica podendo variar entre 480p, 720p ou 1080p ou nas outras resoluções que você definiu. Após dividir a mídia original em pacotes menores, será criado um arquivo chamado de m3u8 que dentro dele terá uma lista de reprodução para cada resolução. Ou seja, terá uma "link" para a lista de reprodução da resolução 1080p, 720p, 480p assim sucessivamente. Portanto os reprodutores utilizaram esse arquivo m3u8 para renderizar o vídeo em seu aparelho. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;No momento é isso é tudo que você precisará saber. Na segunda parte irei entrar em detalhes como funciona o HLS e descrever cenários práticos para melhor entendimento. Logo já adiantando que para desenvolvimento desse projeto, utilizei como protocolo de vídeo o HLS. Mas leia também os outros protocolos que poderiamos ter utilizado&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IIS (Live Smooth Stream): O protocolo de transporte smooth streaming desenvolvido pela Microsoft, também é uma tecnologia de streaming adaptável, e utiliza o mesmo conceito do Apple HLS, ou seja utiliza-se o HTTP para transmitir suas mídias, ao player de destino. Portanto ele é bem semelhante ao HLS, porém com um diferencial, na época em que foi criado, tinha suporte a plataforma de reprodução de vídeo chamada Silverlight, no qual foi descontinuada anos depois.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dash ISO:  É um padrão desenvolvido pela International Organization for Standardization (ISO), esse padrão não é muito diferente dos outros dois, mantendo as mesmas características de comunicação com protocolo HTTP,  reprodução adaptável entre outras características. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Baseado em meu cenário, quais os melhores codecs de vídeo que poderiamos utilizar?
&lt;/h4&gt;

&lt;p&gt;Para responder essa pergunta, primeiro precisamos entender como funcionam os codecs de vídeo. &lt;/p&gt;

&lt;p&gt;Os codecs utilizam algoritmos para comprimir a mídia em um formato compacto. O codec que utilizei para desenvolver o projeto é atualmente um dos mais populares, chamado de  H-264. Ele é amplamente utilizado no mercado, porém se tivéssemos construindo o nosso próprio reprodutor de vídeo e optassemos por utilizar este codec, teríamos que adquirir uma &lt;a href="https://www.via-la.com/licensing-2/avc-h-264/avc-h-264-license-fees/" rel="noopener noreferrer"&gt;licença de uso&lt;/a&gt;. Porém existem outros codecs de código aberto disponíveis no mercado como por exemplo o &lt;a href="https://en.wikipedia.org/wiki/AV1" rel="noopener noreferrer"&gt;AV1 desenvolvido pela Alliance For Open Media&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para desenvolvimento do tech challange, estamos utilizando o AWS MediaConvert portanto não precisamos adquirir a licença de uso, pois a AWS tratou de todos esses assuntos e só precisamos utilizá-lo, sem se preocupar com esses assuntos.&lt;/p&gt;

&lt;p&gt;Para comprimir uma mídia são utilizados algoritmos que usam as técnicas de entropia ou entropy method. O CAVLC e CABAC são alguns desses algoritmos que utilizam as técnicas de entropia para comprimir um arquivo de mídia. Para não estender muito este artigo explicando como funcionam esses algoritmos, irei deixar o link de um outro artigo que ao ler me ajudou muito no entendimento do CAVLC. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Context-adaptive_variable-length_coding" rel="noopener noreferrer"&gt;codificação de comprimento variável adaptável ao contexto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outro ponto importante que precisamos entender é que não é trabalho dos codecs fazerem a fragmentação da mídia original, eles apenas comprimem a mídia já fragmentada para melhor distribuição do conteúdo na rede do usuário. Quem divide a mídia em multiplos pacotes menores são os protocolos de vídeo&lt;/p&gt;

&lt;h4&gt;
  
  
  O que é BitRate?
&lt;/h4&gt;

&lt;p&gt;A configuração do bitrate é essencial para termos uma boa experiência na qualidade da imagem, pois quanto mais baixo, pior será a apresentação do vídeo, porém quanto mais alto melhor a apresentação ou seja melhor será a qualidade da imagem. Para definirmos o melhor bitrate não precisamos fazer cálculos complexos, o youtube tem uma documentação com os bitrate definidos para cada resolução. &lt;a href="https://support.google.com/youtube/answer/2853702?hl=pt-BR&amp;amp;ref_topic=9257892&amp;amp;sjid=6549089735363701325-SA" rel="noopener noreferrer"&gt;Segue a documentação disponibilizada pelo mesmo.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para finalizarmos toda a teoria ainda precisei entender como funciona o AWS MediaConvert no qual é a ferramenta que utilizei para fazer o processamento dos vídeos. Para isso tive que acessar o AWS Skill Builder e fazer alguns cursos que explicavam como utilizar o serviço diretamente na console e também cada configuração que precisaríamos fazer, começando por enviar a mídia original, escolha do codec H-264,  definindo os parâmetros de configuração de áudio e vídeo, e iniciando o processamento da mídia original e separando em pequenos pacotes e armazenando em um bucket no S3.&lt;/p&gt;

&lt;p&gt;Segue os cursos que foram feitos no AWS Skill Builder&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AWS Skill Builder - Setting Up and Configuring AWS Elemental MediaConvert&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS Skill Builder - AWS Elemental MediaConvert Primer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS Skill Builder - Creating Adaptive Bitrate (ABR) Outputs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Após responder todas as questões e aprofundar sobre cada tema, chegou a hora de começarmos o desenvolvimento.&lt;/p&gt;

&lt;h4&gt;
  
  
  Desenvolvimento do projeto
&lt;/h4&gt;

&lt;p&gt;Para integração com o MediaConvert temos que utilizar um SDK da AWS, para isso estou utilizando a &lt;a href="https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/java_mediaconvert_code_examples.html" rel="noopener noreferrer"&gt;versão 2.x do SDK da AWS.&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Antes de iniciar o desenvolvimento, vamos analisar o código apresentado na documentação no item "Create Job". Veja que já conseguimos entender como fazer as configurações do áudio, a resolução que gostaríamos que as nossas mídias tenham, configuração da  taxa de bitrate e codec utilizado. Ou seja, nós temos toda a base necessária para iniciarmos os trabalhos. &lt;/p&gt;

&lt;p&gt;Observe que é um código apresentado na documentação é bastante extenso, porém no tech challenge tive que desenvolver o meu projeto baseado no que já estava disponibilizado na documentação da AWS. Já fiz o trabalho de separar cada recurso em pequenos "blocos" e adicionar as configurações necessárias para que tudo funcione conforme o esperado. Portanto disponibilizo o repositório para que possamos acompanhar e entender onde devemos encaixar cada configuração de vídeo explicada no capítulo "Quais tecnologias utilizamos para processamento de vídeo?"&lt;/p&gt;

&lt;p&gt;O &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos" rel="noopener noreferrer"&gt;repositório&lt;/a&gt;, faz parte da pipeline de processamento de vídeo, nele você encontrará além da integração com o MediaConvert, também verá a integração com o S3 para que possamos pegar a média original e enviá-la para o MediaConvert, encontrará também a integração com o SQS, pois é a partir das mensagens que recebemos da fila que iniciamos a nossa pipeline de processamento de vídeo. &lt;/p&gt;

&lt;p&gt;Para cada mídia enviada ao MediaConvert, precisará ter configurada a trilha de áudio, porém como o nosso foco não é configuração de áudio, vamos deixar da forma padrão conforme visualizamos na documentação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/main/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/audio/TrilhasDeAudio.java" rel="noopener noreferrer"&gt;https://github.com/JonasBarros1998/processamento-de-videos/blob/main/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/audio/TrilhasDeAudio.java&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos configurar os codecs de vídeo, como já foi explicado no capítulo anterior, utilizei o codec H-264, mas dentro do MediaConvert também temos disponíveis outros codecs como Dash ISO, CMAF e Microsoft Smooth Streaming.&lt;/p&gt;

&lt;p&gt;A configuração do codec é bastante extensa, por enquanto não precisamos nos preocupar com todos os parâmetros de configuração, mas um dica valiosa que podemos seguir é entrarmos na console da AWS ir até a ferramenta MediaConvert, adicionar um grupo de saída e ao selecionar Apple HLS, veremos uma série de parâmetros a serem configurados, se observarmos os parâmetros na console AWS e observarmos os parâmetros descritos no código veremos muita semelhança, assim facilitando o nosso desenvolvimento, e o entendimento de cada item. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Para criar o container Apple HLS: &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/main/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/gruposDeSaida/AppleHLSContainer.java" rel="noopener noreferrer"&gt;AppleHLSContainer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Para configurar o segmento de cada pequeno "bloco" da mídia principal: Nesse caso utilizei um segmento igual a 10. Isso quer dizer que cada pacote deverá ter um tamanho de 10 segundos no total. Então o MediaConvert pega a mídia original divide ela em pequenos pacotes de 10 segundos para cada uma da resolução escolhida. Essa configuração está dentro da classe AppleHLSContainer. &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/63ffb536a8d6a89090547b9aa915c3067882b0cf/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/gruposDeSaida/AppleHLSContainer.java#L41" rel="noopener noreferrer"&gt;Configuração do segmento&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Taxa de bits ou bitrate: Para configurar a taxa de bits ideal, conforme disse no capítulo anterior, utilizei as mesmas configurações do youtube para as resoluções 480p, 720p e 1080p. Definição do &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/63ffb536a8d6a89090547b9aa915c3067882b0cf/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/gruposDeSaida/AppleHLSH264.java#L81" rel="noopener noreferrer"&gt;BitRate&lt;/a&gt; e configuração para resoluções &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/63ffb536a8d6a89090547b9aa915c3067882b0cf/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/fabrica/HLSJob.java#L66" rel="noopener noreferrer"&gt;480p&lt;/a&gt;, &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/63ffb536a8d6a89090547b9aa915c3067882b0cf/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/fabrica/HLSJob.java#L74" rel="noopener noreferrer"&gt;720p&lt;/a&gt; e &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/63ffb536a8d6a89090547b9aa915c3067882b0cf/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/fabrica/HLSJob.java#L83" rel="noopener noreferrer"&gt;1080p&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configuração do codec H-264: &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/63ffb536a8d6a89090547b9aa915c3067882b0cf/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/gruposDeSaida/AppleHLSH264.java#L64" rel="noopener noreferrer"&gt;Codec H-264&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Outras configurações de áudio inseridas dentro do codec: &lt;a href="https://github.com/JonasBarros1998/processamento-de-videos/blob/63ffb536a8d6a89090547b9aa915c3067882b0cf/src/main/java/com/br/stream/processamentoDeVideo/infra/processarMidias/gruposDeSaida/AppleHLSH264.java#L105" rel="noopener noreferrer"&gt;Container de áudio&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Portanto, este foi o trabalho desenvolvido para a fase 4 do tech challange da Fiap. Veja que para chegarmos na fase de desenvolvimento tive que entender diversas tecnologias que até momentos atrás não faziam parte do meu escopo de conhecimento. Portanto agora conseguimos entender melhor como o youtube, netflix e outros players de vídeo fazem para reproduzir aquela série que tanto gostamos em nossos aparelhos celulares ou nos computadores. Observe também que só utilizamos ferramentas AWS para salvar as nossas mídias, processá-las e entregá-las ao usuário, a utilização da AWS foi um dos pontos principais para que eu consiga ter agilidade no desenvolvimento, pois é uma nuvem no qual já tenho experiência portanto o desenvolvimento do projeto foi um pouco mais rápido. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>java</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Estratégias de cache | Cache Strategies</title>
      <dc:creator>Jonas Barros</dc:creator>
      <pubDate>Wed, 26 Jun 2024 00:20:24 +0000</pubDate>
      <link>https://dev.to/jonasbarros/estrategias-de-cache-cache-strategies-klk</link>
      <guid>https://dev.to/jonasbarros/estrategias-de-cache-cache-strategies-klk</guid>
      <description>&lt;h4&gt;
  
  
  Estratégias de armazenamento em cache; write-through, read-through, lazy loading e TTL
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Write-Through:&lt;/strong&gt; Essa estratégia é utilizada quando precisamos de consistência dos dados entre o meu banco de dados primário (SQL) e o cache. Para sua implementação correta, precisamos adicionar os dados no cache em todos os métodos que houver uma chamada para escrita de dados relacionada ao banco de dados principal.&lt;br&gt;&lt;br&gt;
Por exemplo, se em uma aplicação eu tiver uma funcionalidade para cadastrar um cliente, após esse cadastro ser concluído, devemos adicionar esses dados também no cache. &lt;/p&gt;

&lt;p&gt;Portanto, uma das vantagens de utilizar essa estratégia é que eu sempre terei os dados atualizados, podendo assim sempre fazer a consulta diretamente no meu cache, ao invés de ir ao banco de dados, assim melhorando o tempo de resposta de uma consulta.&lt;/p&gt;

&lt;p&gt;Sempre teremos os dados atualizados no cache e não iremos ter eventuais inconsistências entre cache e base de dados. &lt;br&gt;
Quando precisarmos realizar uma consulta, podemos ir direto no cache ao invés de ir no banco de dados, resultando assim em um tempo reduzido para consultas e menor tráfego de acesso ao meu banco de dados. &lt;/p&gt;

&lt;p&gt;Umas das desvantagem da utilização do padrão &lt;strong&gt;write-though&lt;/strong&gt;, é o crescimento rápido do armazenamento dos dados em cache, já que se você adicionar no cache dados de toda e qualquer escrita do banco de dados primário, os dados menos acessados poderão ocupar muito espaço, assim inflando o armazenamento.&lt;br&gt;
Adicionar uma TTL e uma boa estratégia de lazy loading, poderá contornar esse problema acima.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;insertDataOnDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic of the insertion &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;insertDataOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic of the insertion&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateClientOnDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic for update&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateClientOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic for update&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;insertNewClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//should insert data into primary database&lt;/span&gt;
  &lt;span class="nf"&gt;insertDataOnDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;//insert data into database cache&lt;/span&gt;
  &lt;span class="nf"&gt;insertDataOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;//should update client into primary database&lt;/span&gt;
  &lt;span class="nf"&gt;updateClientOnDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;//update client into database cache&lt;/span&gt;
  &lt;span class="nf"&gt;updateClientOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lazy Loading:&lt;/strong&gt; Essa estratégia é utilizada quando queremos adicionar aqueles dados que são mais acessados nas aplicações. Para isso temos que implementar essa estratégia da seguinte forma: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;O usuário solicita os dados de uma aplicação.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A aplicação vai primeiro consultar os dados no cache. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se esses dados não existirem, a aplicação vai consultar esses dados no banco.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Em seguida os dados serão adicionados no armazenamento do cache.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Se em uma segunda vez o usuário solicitar esses mesmos dados, não precisamos buscar no banco de dados primário, agora eu busco diretamente no meu cache. Trazendo assim agilidade na consulta dos dados.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vantagens:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A aplicação só irá salvar os dados que realmente utilizamos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Agilidade na hora da consulta dos dados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Menos acessos ao meu banco de dados primário.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Desvantagens:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Se o dado não existir no cache, tenho que passar por 4 passos (conforme listados acima) até retornar os dados ao usuário, gerando assim uma demora maior para retorná-los. Para evitar que todos esses passos sejam executados em sequência, atualize os dados do cache de maneira assíncrona.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dados inconsistentes no cache. Como o cache só irá ser atualizado quando houver alguma consulta, e se por algum momento esse dado ser atualizado no banco e não ser atualizado no cache, isso gerará uma inconsistência entre banco de dados primário e cache. Se você precisa garantir a consistência de dados entre cache e banco de dados primário, implemente também a estratégia de write-through. Porém se a inconsistência não for um problema, siga em frente com essa estratégia sem maiores problemas.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findDataOnDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic of the insertion &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;insertDataOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic of the insertion&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateClientOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic for update&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findDataOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// add logic for search &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findDataOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataOfClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findDataOnDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;insertDataOnCacheDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dataOfClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Referências&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/pt_br/whitepapers/latest/database-caching-strategies-using-redis/caching-patterns.html"&gt;Caching patterns&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.prisma.io/dataguide/managing-databases/introduction-database-caching"&gt;Introduction to database caching&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@mmoshikoo/cache-strategies-996e91c80303"&gt;Cache Strategies&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redis</category>
      <category>elasticsearch</category>
      <category>aws</category>
      <category>programming</category>
    </item>
    <item>
      <title>O que é ACID?</title>
      <dc:creator>Jonas Barros</dc:creator>
      <pubDate>Mon, 04 Jul 2022 23:25:56 +0000</pubDate>
      <link>https://dev.to/jonasbarros/o-que-e-acid-2b57</link>
      <guid>https://dev.to/jonasbarros/o-que-e-acid-2b57</guid>
      <description>&lt;p&gt;O termo foi criado no ano de 1983, por Andreas Reuter e Theo Harder, no qual visa definir os 4 termos que compõem uma transação em um banco de dados. Atomicidade, Consistência, Isolamento e Durabilidade. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;O que é uma transação?&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Uma transação é uma única unidade de trabalho contendo alguma operação do banco de dados como por exemplo o INSERT. Quando iniciamos uma transação, e se por algum motivo uma ou mais operações falharem, nós poderemos fazer o rollback ou seja voltar o banco ao seu estado anterior. Veja o exemplo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1: CREATE SCHEMA acid;

2: CREATE TABLE acid.herois (
3:  nome VARCHAR(255) NOT NULL,
4:      sobrenome VARCHAR(255) NOT NULL,
5:      UNIQUE(nome, sobrenome)
6: );
7:
8: START TRANSACTION;
9: INSERT INTO acid.herois values('Steve', 'Rogers'), ('Tony', 'Stark');
10: COMMIT;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare na &lt;strong&gt;linha 8&lt;/strong&gt;, é nesse ponto que iniciamos uma transação. Se a operação feita na &lt;strong&gt;linha 9&lt;/strong&gt; falhar o commit não será executado e teremos que fazer o rollback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementando na prática os 4 termos do ACID.
&lt;/h3&gt;

&lt;p&gt;Antes de partir para a prática, vamos entender os 4 termos do ACID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atomicidade:&lt;/strong&gt; Todas as operações incluídas dentro de uma transação devem ser realizadas com sucesso, se por acaso alguma operação falhar o rollback deverá ser feito e o banco voltará ao seu estado anterior. Porém se todas as operações forem efetuadas com sucesso a transação deve ser concluída com o comando COMMIT.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistência:&lt;/strong&gt; Todas as regras e restrições que definimos no banco de dados devem ser obedecidas, como por exemplo, tipo dos campos (Boolean, Char, Varchar, Integer, Date, etc), ou seja eu não posso adicionar um texto em um campo onde seu tipo é Integer, relacionamentos por chaves estrangeiras, ou seja todas essas regras devem ser obedecidas. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Isolamento:&lt;/strong&gt; Nenhuma transação poderá interferir no funcionamento da outra transação se as duas estiverem rodando em paralelo. E nenhuma transação poderá visualizar os resultados parciais das outras transações. Ou seja, cada transação tem que ser completamente independente, entenderá melhor esse funcionamento mais adiante, porém já adiantando que essa regra irá mudar de acordo com o tipo do SGBD que você utilizará.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Durabilidade:&lt;/strong&gt; O resultado de uma transação são permanentes e só poderão ser alterados por uma transação subsequente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atomicidade
&lt;/h3&gt;

&lt;p&gt;Por padrão a instrução &lt;code&gt;INSERT&lt;/code&gt; já é atômica, ou seja, eu não preciso adicionar explicitamente o comando &lt;code&gt;START TRANSACTION&lt;/code&gt; como fizemos acima, para dizer que vou iniciar uma transação. Tente executar esses dois inserts abaixo de forma separada no seu editor de SQL e veja o que acontece.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE banco (
    nome VARCHAR (50) NOT NULL,
    saldo MONEY NOT NULL
);

INSERT INTO banco (NOME, SALDO) VALUES ('Tim', 100); 

INSERT INTO banco (NOME, SALDO) VALUES ('Tim'); 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veja que o primeiro &lt;code&gt;INSERT&lt;/code&gt; tudo funcionou, porém já no segundo &lt;code&gt;INSERT&lt;/code&gt; ocorreu um erro porque estamos tentando adicionar um valor NULL em uma coluna &lt;code&gt;NOT NULL&lt;/code&gt;, logo o postgresql não vai adicionar apenas um valor no banco se caso o segundo valor a ser adicionado esteja incorreto.&lt;/p&gt;

&lt;p&gt;Veja agora esse segundo exemplo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1: DO
2: $$
3: DECLARE 
4:  I INT;
5: BEGIN
6:    FOR I IN 1..3 LOOP
7:      INSERT INTO banco (NOME, SALDO) VALUES ('Tim', 100);
8:  END LOOP;
9: END; 
10: $$;
11: 
12: DO
13: $$
14: DECLARE 
15: I INT;
16: BEGIN
17:    FOR I IN 1..3 LOOP
18:     INSERT INTO banco (NOME, SALDO) VALUES ('Martin', 300);
19: END LOOP;
20: END; 
21: $$;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código acima, fizemos um laço com 3 repetições, e dentro dele temos uma simples instrução &lt;code&gt;INSERT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Após executar o código acima, veja que os valores foram adicionados corretamente e todas as instruções passaram sem maiores problemas. &lt;br&gt;
Agora apague tudo que foi adicionado na tabela, porque vamos forçar um erro no segundo &lt;code&gt;INSERT&lt;/code&gt; na linha 18 para ver o que acontece.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1: DO
2: $$
3: DECLARE 
4:  I INT;
5: BEGIN
6:    FOR I IN 1..3 LOOP
7:      INSERT INTO banco (NOME, SALDO) VALUES ('Tim', 100);
8:  END LOOP;
9: END; 
10: $$;
11: 
12: DO
13: $$
14: DECLARE 
15: I INT;
16: BEGIN
17:    FOR I IN 1..3 LOOP
18:     INSERT INTO banco (NOME, SALDO) VALUES ('Martin');
19: END LOOP;
20: END; 
21: $$;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veja que apaguei o saldo da conta do Martin, porém a coluna saldo não aceita valores do tipo &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ao executar esse bloco de código repare houve um erro na linha 18, onde estamos tentando inserir um valor do tipo &lt;code&gt;NULL&lt;/code&gt; em uma coluna que não permite tais valores, porém se rodarmos o comando &lt;code&gt;SELECT * FROM banco;&lt;/code&gt; veja que nenhum valor foi adicionado, nem mesmo os valores contidos no &lt;code&gt;INSERT&lt;/code&gt; da linha 7. Então podemos afirmar que esse conjunto de instruções são atômicas, porque toda a instrução tem que ser bem-sucedida para que os dados sejam adicionados ao banco, se por acaso alguma instrução falhar nada será modificado em nossas tabelas.&lt;/p&gt;

&lt;p&gt;Isso acontece pelo seguinte motivo, repare na linha 16 temos a instrução chamada &lt;code&gt;BEGIN&lt;/code&gt; essa instrução serve para iniciarmos uma transação, e o &lt;code&gt;COMMIT&lt;/code&gt; para confirmar. Mas repare que eu não adicionei nenhuma instrução &lt;code&gt;COMMIT&lt;/code&gt; ao código, porque especificamente no postgresql quando se inicia uma transação e não existe uma instrução &lt;code&gt;COMMIT&lt;/code&gt; ele executa a transação em modo de &lt;strong&gt;auto commit&lt;/strong&gt; veja com mais detalhes na &lt;a href="https://www.postgresql.org/docs/current/sql-begin.html"&gt;documentação&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consistência
&lt;/h3&gt;

&lt;p&gt;O exemplo acima explica bem como funciona a consistência do banco de dados. Repare que não conseguimos adicionar um valor do tipo &lt;code&gt;NULL&lt;/code&gt; em uma coluna do tipo &lt;code&gt;MONEY&lt;/code&gt;. Também não é possível adicionar uma palavra qualquer ao invés de um valor monetário.&lt;br&gt;
&lt;code&gt;INSERT INTO banco (NOME, SALDO) VALUES ('Martin', 'money');&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Durabilidade
&lt;/h3&gt;

&lt;p&gt;Toda a transação é permanente e só pode ser desfeita por uma outra transação. &lt;br&gt;
Após o &lt;code&gt;COMMIT&lt;/code&gt; de uma transação os dados devem ser salvos ou excluídos de forma definitiva no banco de dados, não podendo haver erros por falha de hardware por exemplo. &lt;/p&gt;
&lt;h3&gt;
  
  
  Isolamento
&lt;/h3&gt;

&lt;p&gt;No postgresql existem 4 tipos de isolamento; Read Uncommitted, Read Committed, Repeatable Read, Serializable, mas  por padrão ele utiliza o Read Committed. Com o comando &lt;code&gt;SET TRANSACTION&lt;/code&gt; podemos alterar esse comportamento.&lt;br&gt;
Para fins didáticos vamos entender apenas o tipo Read Committed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;read commited&lt;/strong&gt;&lt;br&gt;
Esse nível de isolamento funciona da seguinte maneira, por exemplo o comando &lt;code&gt;SELECT&lt;/code&gt; ele vai ler apenas os dados que foram confirmados. Isso acontece porque o &lt;code&gt;SELECT&lt;/code&gt; lê um snapshot do banco de dados antes do início da leitura. O comando SELECT também pode ler as alterações que foram feitas dentro da mesma transação, mesmo que não tenham sido confirmadas. Veja o exemplo abaixo. (Ainda não execute a instrução COMMIT).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;START TRANSACTION;
    INSERT INTO banco (nome, saldo) VALUES ('Mark', '200');
    SELECT * FROM banco;
/*COMMIT*/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veja que o &lt;code&gt;SELECT&lt;/code&gt; leu os dados que ainda não foram confirmados.&lt;/p&gt;

&lt;p&gt;Em seguida, abra mais uma instância do seu editor de SQL e faça uma nova conexão com o banco, depois digite a instrução SQL abaixo, para verificarmos se ele conseguirá ler as informações que adicionamos acima, porém ainda não confirmadas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM banco;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veja que nada nos retornou. Agora descomente e execute a instrução &lt;code&gt;COMMIT&lt;/code&gt; que fizemos acima, e posteriormente rode a instrução &lt;code&gt;SELECT&lt;/code&gt; que fizemos fora da transação. Tudo funcionou como esperado, após confirmamos a transação os dados foram adicionados no banco e o select que estava fora da transação conseguiu ler os dados que foram inseridos na tabela. &lt;/p&gt;

&lt;p&gt;Mas se tivermos 2 transações em andamento de forma paralela, a primeira transação excluindo linha com o nome Mark já a segunda atualizando essa mesma linha. O Read Committed irá tratá-las da seguinte maneira.&lt;br&gt;
Se temos duas transações rodando em paralelo, se a primeira transação for uma exclusão, a segunda transação irá aguardar a confirmação dos resultados da primeira transação. Se a primeira transação for confirmada, a segunda transação irá ignorar a linha excluída pela primeira transação. Porém se as atualizações forem revogadas a segunda transação irá prosseguir normalmente com as suas atualizações.&lt;/p&gt;

&lt;h4&gt;
  
  
  Referências:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/tutorial-transactions.html"&gt;Transactions&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.postgresql.org/docs/current/transaction-iso.html"&gt;Transacions Isolation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sql</category>
      <category>postgres</category>
    </item>
  </channel>
</rss>
