<?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: Renato Suero</title>
    <description>The latest articles on DEV Community by Renato Suero (@renatosuero).</description>
    <link>https://dev.to/renatosuero</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%2F27627%2Fb522b6b8-3323-402c-be98-10faa62f08f7.png</url>
      <title>DEV Community: Renato Suero</title>
      <link>https://dev.to/renatosuero</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/renatosuero"/>
    <language>en</language>
    <item>
      <title>Conectando Dois Bancos PostgreSQL com FDW (DataLink do Heroku)</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Mon, 11 Aug 2025 11:00:00 +0000</pubDate>
      <link>https://dev.to/renatosuero/conectando-dois-bancos-postgresql-com-fdw-datalink-do-heroku-43kn</link>
      <guid>https://dev.to/renatosuero/conectando-dois-bancos-postgresql-com-fdw-datalink-do-heroku-43kn</guid>
      <description>&lt;p&gt;&lt;a href="https://renatosuero.dev.br/posts/conectando-dois-bancos-de-dados-com-fdw/" rel="noopener noreferrer"&gt;Postado originalmente&lt;br&gt;&lt;br&gt;
&lt;/a&gt;É muito comum quando temos 2 sistemas que se relacionam em algum momento um precisar conectar no outro banco de dados. Seja pela aplicação(falarei sobre em outro post) ou mesmo direto numa consulta no banco de dados.&lt;/p&gt;

&lt;p&gt;Imagina conseguir fazer uma consulta onde fazemos um inner join usando uma tabela de cada banco de dados, como a seguir estando conectado no banco de dados loja e consultando produto que vem de catalogo:&lt;br&gt;
&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 vendas v inner join produtos p on p.id=v.produto_id  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Quanto usamos serviços como Heroku temos isso via interface(chamado data link) e outros lugares com possíveis outros nomes, mas por baixo dos panos estão usando uma extensão do Postgres chamada [fdw](&lt;a href="https://www.postgresql.org/docs/current/postgres-fdw.html" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/current/postgres-fdw.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Meu objetivo é mostrar como conseguimos alcançar isso para o ambiente de desenvolvimento que é onde vamos escrever esse código então precisamos validá-lo&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuração
&lt;/h3&gt;

&lt;p&gt;Para começar eu vou deixar o script para criação de 2 bancos de dados para seguirmos o tutorial&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create database catalogo
-- Cria a tabela 'produtos'
CREATE TABLE produtos (
    id SERIAL PRIMARY KEY,
    nome VARCHAR(255) NOT NULL,
    quantidade INT NOT NULL,
    valor DECIMAL(10, 2) NOT NULL
);

-- Insere uma lista de 10 produtos na tabela
INSERT INTO produtos (nome, quantidade, valor) VALUES
('Notebook Gamer', 15, 7500.50),
('Monitor 4K 27"', 25, 1899.90),
('Teclado Mecânico RGB', 50, 350.00),
('Mouse Sem Fio Ergonômico', 80, 120.75),
('Headset 7.1 Surround', 40, 499.99),
('Cadeira Gamer Confort', 20, 1200.00),
('SSD NVMe 1TB', 60, 850.00),
('Placa de Vídeo RTX 4070', 10, 4500.00),
('Memória RAM 16GB DDR5', 100, 650.25),
('Webcam Full HD', 75, 250.00);
&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;create database loja
-- Cria a tabela 'usuarios'
CREATE TABLE usuarios (
    id SERIAL PRIMARY KEY,
    nome VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL UNIQUE
);

-- Cria a tabela 'vendas'
-- Esta tabela se relaciona com 'usuarios' e 'produtos'
CREATE TABLE vendas (
    id SERIAL PRIMARY KEY,
    usuario_id INT NOT NULL,
    produto_id INT NOT NULL,
    quantidade INT NOT NULL CHECK (quantidade &amp;gt; 0),
    data_venda TIMESTAMP WITH TIME ZONE DEFAULT NOW(),

    -- Define as chaves estrangeiras para garantir a integridade dos dados
    CONSTRAINT fk_usuario FOREIGN KEY(usuario_id) REFERENCES usuarios(id)
);
-- II. INSERIR DADOS DE EXEMPLO

-- Insere 10 usuários na tabela 'usuarios'
INSERT INTO usuarios (nome, email) VALUES
('Ana Silva', 'ana.silva@email.com'),
('Bruno Costa', 'bruno.costa@email.com'),
('Carlos Pereira', 'carlos.pereira@email.com'),
('Daniela Martins', 'daniela.martins@email.com'),
('Eduardo Almeida', 'eduardo.almeida@email.com'),
('Fernanda Lima', 'fernanda.lima@email.com'),
('Gustavo Oliveira', 'gustavo.oliveira@email.com'),
('Helena Souza', 'helena.souza@email.com'),
('Igor Santos', 'igor.santos@email.com'),
('Juliana Ribeiro', 'juliana.ribeiro@email.com');

-- Insere 50 registros de vendas na tabela 'vendas'
-- As datas são variadas para simular um histórico de vendas.
INSERT INTO vendas (usuario_id, produto_id, quantidade, data_venda) VALUES
(1, 3, 1, '2025-07-01 10:30:00'),
(5, 1, 1, '2025-07-01 11:15:00'),
(2, 5, 2, '2025-07-02 14:00:00'),
(10, 8, 1, '2025-07-03 09:05:00'),
(3, 7, 1, '2025-07-04 18:20:00'),
(7, 2, 1, '2025-07-05 12:00:00'),
(4, 10, 3, '2025-07-06 16:45:00'),
(8, 4, 1, '2025-07-07 11:50:00'),
(6, 6, 1, '2025-07-08 13:10:00'),
(9, 9, 2, '2025-07-09 10:00:00'),
(1, 4, 1, '2025-07-10 15:00:00'),
(2, 8, 1, '2025-07-11 17:25:00'),
(5, 2, 1, '2025-07-11 19:00:00'),
(7, 1, 1, '2025-07-12 08:30:00'),
(3, 9, 4, '2025-07-13 11:40:00'),
(10, 5, 1, '2025-07-14 20:00:00'),
(4, 7, 1, '2025-07-15 21:05:00'),
(6, 3, 2, '2025-07-16 09:15:00'),
(8, 6, 1, '2025-07-17 10:00:00'),
(1, 10, 1, '2025-07-18 14:55:00'),
(9, 1, 1, '2025-07-19 16:20:00'),
(5, 5, 1, '2025-07-20 18:30:00'),
(2, 7, 2, '2025-07-21 12:10:00'),
(7, 4, 3, '2025-07-22 13:00:00'),
(3, 2, 1, '2025-07-22 14:40:00'),
(8, 8, 1, '2025-07-23 09:00:00'),
(4, 9, 1, '2025-07-23 11:20:00'),
(10, 3, 1, '2025-07-24 16:00:00'),
(6, 1, 1, '2025-07-24 17:00:00'),
(1, 6, 1, '2025-07-25 19:10:00'),
(2, 10, 2, '2025-07-26 10:45:00'),
(5, 4, 1, '2025-07-26 11:00:00'),
(9, 5, 1, '2025-07-26 15:30:00'),
(7, 7, 1, '2025-07-27 13:25:00'),
(3, 1, 1, '2025-07-27 14:00:00'),
(4, 8, 1, '2025-07-28 10:10:00'),
(8, 2, 2, '2025-07-28 11:30:00'),
(10, 9, 1, '2025-07-28 12:00:00'),
(6, 5, 1, '2025-07-29 18:00:00'),
(1, 7, 1, '2025-07-29 18:45:00'),
(9, 3, 3, '2025-07-29 20:15:00'),
(5, 6, 1, '2025-07-30 09:30:00'),
(2, 4, 1, '2025-07-30 10:00:00'),
(7, 10, 1, '2025-07-30 14:20:00'),
(3, 8, 1, '2025-07-30 15:00:00'),
(4, 1, 1, '2025-07-30 16:10:00'),
(8, 9, 2, '2025-07-30 17:40:00'),
(10, 2, 1, '2025-07-31 08:50:00'),
(6, 7, 1, '2025-07-31 09:00:00'),
(1, 5, 1, '2025-07-31 09:15:00');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora que temos 2 bancos de dados, podemos começar.Temos alguns passos para configurar a conexão, sendo eles:&lt;/p&gt;

&lt;p&gt;Criar a extensão&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# CREATE EXTENSION IF NOT EXISTS postgres_fdw;
CREATE EXTENSION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checando se tudo está ok&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# select * from pg_extension;
   oid   |   extname    | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
---------+--------------+----------+--------------+----------------+------------+-----------+--------------
   13895 | plpgsql      |       10 |           11 | f              | 1.0        |           |
 7549345 | postgres_fdw |       10 |         2200 | t              | 1.1        |           |
(2 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Criar o servidor no banco de dados:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Criei um server chamado foreigndb_fdw, vamos usar esse nome na hora de importar as tabelas, tbm fiz a configuração para o outro banco de dados, basicamente mudou o dbname já que ambos rodam localmente&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# CREATE SERVER foreigndb_fdw FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '127.0.0.1', port '5432', dbname 'catalogo');
CREATE SERVER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checando se tudo está ok&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# \des
               List of foreign servers
     Name      |    Owner     | Foreign-data wrapper
---------------+--------------+----------------------
 foreigndb_fdw | fdwuser      | postgres_fdw
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Criar user mapping:&lt;/p&gt;

&lt;p&gt;Podemos fazer manual trocando fdwuser para o usuário que vamos conectar ou usar o próximo comando que vai selecionar o usuário conectado &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Eu já tenho um usuário chamado fdwuser, então uso o mesmo assim não preciso configurar permissões e outras configurações, como é um ambiente local podemos deixar isso simples. No primeiro comando eu passo a mesma senha que uso para conectar, na segunda opção não há senha então só criar o mapping do usuário&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# CREATE USER MAPPING FOR fdwuser SERVER foreigndb_fdw OPTIONS (user 'fdwuser', password 'secret');
CREATE USER MAPPING
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comando lendo o usuário logado, o usuário que estamos executando os comandos&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT format('CREATE USER MAPPING FOR %I SERVER foreigndb_fdw OPTIONS (user %L)', current_user, current_user) \gexec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checando se tudo está ok&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# select * from pg_user_mapping;
   oid   | umuser | umserver |      umoptions
---------+--------+----------+---------------------
 7549353 |     10 |  7549352 | {user=fdwuser}
(1 row)
loja=# select * from pg_user_mappings;
  umid   |  srvid  |    srvname    | umuser |   usename    |      umoptions
---------+---------+---------------+--------+--------------+---------------------
 7549353 | 7549352 | foreigndb_fdw |     10 | fdwuser      | {user=fdwuser}
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois que fizemos as configurações agora falta um último passo, importar as tabelas utilizadas no banco de dados. Aqui eu tenho algumas notas que farei na sequência, mas vou deixar um exemplo de como funcionaria.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# IMPORT FOREIGN SCHEMA public                                                                                                             FROM SERVER foreigndb_fdw                                                                                                                     INTO public;
IMPORT FOREIGN SCHEMA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notas sobre o import
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sempre que criar novas tabelas precisará fazer o import para que traga a nova tabela;&lt;/li&gt;
&lt;li&gt;Caso tenha conflito com nome de tabela, ambos banco de dados tendo uma tabela com o mesmo nome, podemos criar um schema. Note que que comando acima é feito no final &lt;strong&gt;INTO public&lt;/strong&gt;  troque public para o nome do novo schema, e na hora da consulta tem que fazer &lt;em&gt;nome-schema.tabela&lt;/em&gt;  se criamos um schema catalogo seria assim &lt;strong&gt;catalogo.produtos&lt;/strong&gt;  &lt;/li&gt;
&lt;li&gt;O import não traz enum ou coisas do tipo, neste caso eu copio o script de criação e executo no outro banco de dados, assim ele funcionará porque agora terá esses items customizados&lt;/li&gt;
&lt;li&gt;Eu fiz um import de todas tabelas, mas podemos restringir com algumas opções:

&lt;ul&gt;
&lt;li&gt;EXCEPT para excluir tabelas,  IMPORT FOREIGN SCHEMA public EXCEPT (produtos)&lt;/li&gt;
&lt;li&gt;LIMIT TO para selecionar apenas algumas  IMPORT FOREIGN SCHEMA public LIMIT TO (produtos)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deletando tudo
&lt;/h3&gt;

&lt;p&gt;Hora de limpar a casa, detelando a extensão já irá remover as configurações de server, users mappings e o import das tabelas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loja=# DROP EXTENSION IF EXISTS postgres_fdw CASCADE;
NOTICE:  drop cascades to 3 other objects
DETAIL:  drop cascades to server foreigndb_fdw
drop cascades to user mapping for renato.suero on server foreigndb_fdw
drop cascades to foreign table produtos
DROP EXTENSION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>postgres</category>
      <category>database</category>
      <category>braziliandevs</category>
      <category>postgressql</category>
    </item>
    <item>
      <title>Lidando com concorrências no banco de dados 🇧🇷</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Sun, 25 Oct 2020 12:07:27 +0000</pubDate>
      <link>https://dev.to/renatosuero/lidando-com-concorrencias-no-banco-de-dados-1jhf</link>
      <guid>https://dev.to/renatosuero/lidando-com-concorrencias-no-banco-de-dados-1jhf</guid>
      <description>&lt;p&gt;Você já ouviu essa pergunta ? "O que acontece se 2 pessoas executarem a ação ao mesmo tempo?"(no contexto de um serviço web com o banco de dados). Algumas respostas possíveis(se conhece outras me diz ai).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Transações estão ai para resolver isso.&lt;/li&gt;
&lt;li&gt;Não sei (simples,direto e principalmente honesto).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Beleza, vamos criar um cenário para que possamos ter o contexto em comum. Podemos olhar para esse problema pensando em reserva de assentos/quartos, estoque de produtos,qualquer problema onde 2 pessoas podem alterar o mesmo registro, etc...&lt;br&gt;
Vamos trabalhar com um cinema. Temos uma tabela com os assentos 1-5(sim é um cinema muito pequeno, mas garanto que a qualidade é muito boa).&lt;/p&gt;

&lt;p&gt;Vamos ter uma tabela assentos com os registros para cada assento e o nome de quem reservou. A tabela será simplesmente isso e eu farei as inserções dos assentos com cliente vazio oq significa disponível.&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;database&lt;/span&gt; &lt;span class="n"&gt;cinema&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;assentos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; 
   &lt;span class="n"&gt;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;cliente&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;''&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;assentos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&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="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;postgres@localhost:cinema&amp;gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from assentos&lt;span class="p"&gt;;&lt;/span&gt;                                              
+------+-----------+
| &lt;span class="nb"&gt;id&lt;/span&gt;   | cliente   |
|------+-----------|
| 1    |           |
| 2    |           |
| 3    |           |
| 4    |           |
| 5    |           |
+------+-----------+
SELECT 5
Time: 0.018s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;o fluxo da reserva vai ser:&lt;/p&gt;

&lt;p&gt;Checar se o assento está disponível&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Caso negativo: "Retornar um erro avisando que o assento não está disponível";&lt;/li&gt;
&lt;li&gt;Caso positivo: Reservar o assento e retornar uma mensagem avisando que foi reservado;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No sql seria algo assim&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;begin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;assentos&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;///&lt;/span&gt; &lt;span class="n"&gt;caso&lt;/span&gt; &lt;span class="n"&gt;retorne&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;assentos&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Renato'&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;Commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Criei um código para mostrar isso, não vou mostrar aqui porque o objetivo é executar as instruções acima, mas você pode ver o código nesse &lt;a href="https://gist.github.com/renatosuero/1cc0a031c485542d41276cd718382eaa" rel="noopener noreferrer"&gt;link&lt;/a&gt;.(você pode ver isso funcionando, mas não recomendo esse código, eu fiz ele rápido só para mostrar meu ponto porque só com o sql não seria tão divertido).&lt;/p&gt;



&lt;p&gt;Legal temos nossa API para reservar assentos no cinema :), massss o que acontece se durante o processo de reserva tivermos alguma lentidão no servidor ou mesmo se tivermos algum processo ali no meio entre a consulta e reserva(por ex. enviar a informação sobre a reserva para outro serviço)?&lt;/p&gt;

&lt;p&gt;Vou Adicionar um sleep antes do update para simular o cenário, caso o cliente seja Henrique(por que Henrique?, porque ele é um vacilão 🙂) assim podemos responder à pergunta anterior. &lt;/p&gt;

&lt;p&gt;Vou mandar duas requisições usando o curl para que fique tudo na mesma imagem. E ai quer dar um palpite? quem leva o quarto Henrique ou Renato ?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Olhe em fullscreen para ver todas panes do meu tmux &lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;



&lt;p&gt;Brincadeiras de lado, o que rolou foi que quando o Henrique enviou o pedido a API fez o fluxo que combinamos, porém ela deu uma pausa para que desse tempo de fazermos outro pedido.&lt;br&gt;
O outro pedido fez o mesmo processo e na primeira parte confirmou que o assento estava livre então poderia avançar e assim fez executando o update para o Renato, quando o sleep terminou o update do Henrique foi feito, nesse caso como foi o último ele levou o assento(apesar de ambos terem o retorno de sucesso). Agora se Renato também tivesse uma lentidão e fosse maior que Henrique(executasse o update por último) ele/eu levaria o assento.  &lt;/p&gt;

&lt;p&gt;Legal agora podemos começar o post sobre esse assunto. Existe algumas opções de lock que podemos bloquear o dados seja uma tabela ou registro(nosso caso).&lt;/p&gt;

&lt;p&gt;A solução é bem simples, mas infelizmente não muito conhecida (motivo pelo qual eu escrevo este post).&lt;/p&gt;

&lt;p&gt;Na nossa query , vamos adicionar mais 2 palavras, &lt;strong&gt;FOR UPDATE&lt;/strong&gt; Ficando assim:&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="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;assentos&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Essa instrução nova vai dar um lock nesse registro não permitindo outras consultas no registro. Assim quando a próxima query tentar consultar o assento 5 nesse caso, vai ficar esperando até que quem deu o bloqueio(a transação que fez o pedido de reserva) execute o Commit ou Rollback.&lt;br&gt;
 Vamos ver novamente o resutlado agora com o essa alteração.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Olhe em fullscreen para ver todas panes do meu tmux &lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;



&lt;p&gt;Legal né? com duas palavras resolvemos um problema de reservar o mesmo assento para para mais pessoas.&lt;/p&gt;

&lt;p&gt;Uma boa notícia para quem usa o GORM é que ele tem suporte para essa &lt;a href="https://gorm.io/docs/advanced_query.html#Locking-FOR-UPDATE" rel="noopener noreferrer"&gt;feature&lt;/a&gt;&lt;br&gt;
Beleza se vc não quis clicar tá aqui o exemplo :)&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="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Clauses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Locking&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Strength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"UPDATE"&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;assentos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;"id = $1 and cliente =''"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma forma que você poderia resolver sem precisar do "lock" seria fazer algo assim(obrigado Henrique)&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="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;assentos&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;assentos&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Henrique'&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para o cenário simples que criei sim é uma solução que funcionaria bem, a única coisa diferente é que a API precisaria ver o retorno &lt;strong&gt;RowsAffected&lt;/strong&gt; para saber se houve a reserva(update aconteceu e retornaria 1 RowsAffected,caso 0 significa que não encontrou). Para esse cenário de um campo fica fácil validar se o campo ainda está no estado anterior(cliente is null) mas para a vida real ou algo menos simples que um campo para atualizar isso te obrigaria a checar todos campos que vai fazer o update. Acho que usando o &lt;strong&gt;FOR UPDATE&lt;/strong&gt; você resolve isso de uma maneira mais "limpa/simples".&lt;/p&gt;

&lt;p&gt;Bom era isso que tinha para fazer hoje, espero que tenham gostado e que te ajude de alguma forma =)&lt;/p&gt;

</description>
      <category>go</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Avoid duplicated requests with singleflight</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Sun, 24 May 2020 14:17:46 +0000</pubDate>
      <link>https://dev.to/renatosuero/avoid-duplicated-requests-with-singleflight-53i3</link>
      <guid>https://dev.to/renatosuero/avoid-duplicated-requests-with-singleflight-53i3</guid>
      <description>&lt;p&gt;Do you have any endpoints which need to process a lot of things, it consumes third-party data, it's slow, etc... And to help these endpoints receive a lot of simultaneous requests (something you load on your home page for all users and the content is the same, for example some statistics).&lt;/p&gt;

&lt;p&gt;Each time that endpoint is called your eyes are filled with tears. That is about to change :) I'll tell you how.&lt;br&gt;
We will use the package &lt;a href="https://pkg.go.dev/golang.org/x/sync/singleflight?tab=doc" rel="noopener noreferrer"&gt;singleflight&lt;/a&gt;.In words of the package:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Package singleflight provides a duplicate function call suppression mechanism." &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The idea of the package is, you create a key to identify the request and when there're other requests with the same key, it will wait for the answer which is processing for another request. When the request returns the result, it will share with the other requests were waiting for the result, therefore avoiding multiples requests/slow process.&lt;/p&gt;

&lt;p&gt;Let's see the code, I've created an API to see the package running, you can see the code [here]. (&lt;a href="https://github.com/renatosuero/devto-posts/tree/master/singleflight" rel="noopener noreferrer"&gt;https://github.com/renatosuero/devto-posts/tree/master/singleflight&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I've created an HTTP service that will consume data that comes from an external API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "time"
)

func main() {
    var requestGroup singleflight.Group
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("calling the endpoint")
        response, err := http.Get("https://jsonplaceholder.typicode.com/photos")

        if err != nil {
            fmt.Print(err.Error())
            os.Exit(1)
        }

        responseData, err := ioutil.ReadAll(response.Body)
        if err != nil {
            log.Fatal(err)
        }
        time.Sleep(2 * time.Second)
        w.Write(responseData)
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accessing &lt;a href="http://127.0.0.1:3000/" rel="noopener noreferrer"&gt;http://127.0.0.1:3000/&lt;/a&gt; it willl call the API &lt;strong&gt;jsonplaceholder&lt;/strong&gt;, in order to become interesting I've added 2 seconds for sleeping to simulate the process is slowlest.&lt;/p&gt;

&lt;p&gt;Let's use &lt;a href="https://github.com/tsenart/vegeta" rel="noopener noreferrer"&gt;vegeta&lt;/a&gt;, the goal is to execute a lot of requests to see singleflight shine. I defined to execute 10 requests per second and the duration will be 1 second.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "GET http://localhost:3000/" | vegeta attack -duration=1s -rate=10 | tee results.bin | vegeta report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you can see the result of Vegeta and the output of our service:&lt;br&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%2Fi%2Fdc85lzqhuwi8tnap6zvs.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%2Fi%2Fdc85lzqhuwi8tnap6zvs.png" alt="Alt Text" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, all requests called the external API.&lt;/p&gt;

&lt;p&gt;Let's see singleflight shine now, we'll use the same configurations to run Vegeta again.&lt;/p&gt;

&lt;p&gt;In this code I added a new endpoint /singleflight, in the function &lt;strong&gt;requestGroup.Do&lt;/strong&gt;, I defined the key as s*singleflight*, now the request will verify if there's a processing running (using that key) , if there's a key, it won't call and it'll wait for the result of the call it is processing.&lt;br&gt;
I added a print in the terminal to indicate when the request waits for result and uses the shared result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Because the pacage isn't a starndard library until now, you have to add him in your go path,go mod, vendor,etc..
import "golang.org/x/sync/singleflight"
var requestGroup singleflight.Group
//para este endpoint funcionar você precisa importar o pacote singleflight e criar essa variável(eu sei global e tal, mas para este post é suficiente).
    http.HandleFunc("/singleflight", func(w http.ResponseWriter, r *http.Request) {
        res, err, shared := requestGroup.Do("singleflight", func() (interface{}, error) {
            fmt.Println("calling the endpoint")
            response, err := http.Get("https://jsonplaceholder.typicode.com/photos")

            if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return nil, err
            }
            responseData, err := ioutil.ReadAll(response.Body)
            if err != nil {
                log.Fatal(err)
            }
            time.Sleep(2 * time.Second)
            return string(responseData), err
        })

        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        result := res.(string)
        fmt.Println("shared = ", shared)
        fmt.Fprintf(w, "%q", result)
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vegeta again&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "GET http://localhost:3000/" | vegeta attack -duration=1s -rate=10 | tee results.bin | vegeta report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fi%2Fm4ynk0mhox6n2fx5cyck.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%2Fi%2Fm4ynk0mhox6n2fx5cyck.png" alt="Alt Text" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recommend you execute the code+vegeta and see it executing in your machine.&lt;br&gt;
In the first endpoint, you'll see all the requests are executed and the log shows the calls. &lt;br&gt;
In the second one, you'll see one request, and suddenly 10 true indicating all requests used the shared result.&lt;/p&gt;

&lt;p&gt;That's an amazing resource, let's think of endpoints we have a heavy/slow process, or you pay by external requests. In the latter, not only it helps reducing processing power, but also saves you money by avoiding duplicated calls .&lt;br&gt;
Another thing, I'm using an HTTP service, but it could be anything, for example it could be a database query, a worker, etc...&lt;/p&gt;

&lt;p&gt;Well, that's it folks. I hope it helps you as it helped me knowing this cool package, I'd like to thank &lt;a href="https://twitter.com/henriquev" rel="noopener noreferrer"&gt;Henrique&lt;/a&gt; to show me that, and &lt;a href="http://linkedin.com/in/andre-mota" rel="noopener noreferrer"&gt;André Mota&lt;/a&gt; for your valuable review. &lt;br&gt;
The package has an option to "forget" the key and another one that the result returns by channels. You can for example, define a timeout, after X time you defined, cancel the key or by channel.&lt;/p&gt;

</description>
      <category>go</category>
      <category>performance</category>
    </item>
    <item>
      <title>Evitando requisições duplicadas com singleflight 🇧🇷</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Sun, 12 Apr 2020 14:55:41 +0000</pubDate>
      <link>https://dev.to/renatosuero/evitando-requisicoes-duplicadas-com-singlefight-5fj0</link>
      <guid>https://dev.to/renatosuero/evitando-requisicoes-duplicadas-com-singlefight-5fj0</guid>
      <description>&lt;p&gt;Você tem algum endpoint que precisa processar muita coisa, consome dados de terceiros, lento, etc.... E para ajudar esse endpoint recebe muitas requisições simultâneas( algo que carrega na tua página inicial para todos users e tem o mesmo conteúdo)&lt;/p&gt;

&lt;p&gt;Cada vez que aquele endpoint é chamado seus olhos se enchem de lágrimas, pois então isso vai mudar :) e vou te contar como. &lt;br&gt;
Vamos usar o pacote &lt;a href="https://pkg.go.dev/golang.org/x/sync/singleflight?tab=doc" rel="noopener noreferrer"&gt;singleflight&lt;/a&gt;. Nas palavras do pacote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Package singleflight provides a duplicate function call suppression mechanism." &lt;br&gt;
 "O pacote singleflight fornece um mecanismo de supressão de chamada de função duplicado."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A idéia do pacote é, você cria uma chave para identificar a requisição e quando houver outras requisições com a mesma chave ela vai aguardar a resposta que está em andamento de outra request. Quando a request retornar com o resultado ela compartilhará com as outras requests que estavam esperando pelo resultado, assim evitando múltiplas chamadas/processos pesados.&lt;/p&gt;

&lt;p&gt;Chega de papo e vamos ver código, afinal é disso que gostamos :). Criei uma api para que possamos ver o pacote em ação, você pode ver o código no &lt;a href="https://github.com/renatosuero/devto-posts/tree/master/singleflight" rel="noopener noreferrer"&gt;repositório&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Criei um serviço http que consome dados vindos de uma api externa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main
import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "time"
)
func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("calling the endpoint")
        response, err := http.Get("https://jsonplaceholder.typicode.com/photos")
        if err != nil {
            fmt.Print(err.Error())
            os.Exit(1)
        }
        responseData, err := ioutil.ReadAll(response.Body)
        if err != nil {
            log.Fatal(err)
        }
        time.Sleep(2 * time.Second)
        w.Write(responseData)
    })
    http.ListenAndServe(":3000", nil)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando você acessar &lt;a href="http://127.0.0.1:3000/" rel="noopener noreferrer"&gt;http://127.0.0.1:3000/&lt;/a&gt; ele vai chamar pela api jsonplaceholder, para tornar mais interessante eu adicionei um sleep de 2 segundos para simular que o processo é mais lento.&lt;/p&gt;

&lt;p&gt;Agora vamos usar o &lt;a href="https://github.com/tsenart/vegeta" rel="noopener noreferrer"&gt;vegeta&lt;/a&gt; a idéia aqui é executar várias requests para ver o singleflight brilhar. Eu defino para executar 10 requests por segundo e a duração de 1 segundo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "GET http://localhost:3000/" | vegeta attack -duration=1s -rate=10 | tee results.bin | vegeta report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui você pode ver o resultado do Vegeta e o output do nosso serviço:&lt;br&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%2Fi%2Fdc85lzqhuwi8tnap6zvs.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%2Fi%2Fdc85lzqhuwi8tnap6zvs.png" alt="Alt Text" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podemos ver todas requests chamaram a api externa.&lt;/p&gt;

&lt;p&gt;Agora vamos ver o singleflight brilhar, usaremos as mesmas configurações do vegeta.&lt;/p&gt;

&lt;p&gt;Neste código eu adicionei um novo endpoint /singleflight, na chamada da função &lt;strong&gt;requestGroup.Do()&lt;/strong&gt; eu defini a chave como singleflight, agora a request vai verificar se há um processo em andamento, caso sim ele aguarda o resultado.&lt;br&gt;
Adicionei um print no terminal para indicar quando a request aguarda pelo resultado e usa a resposta compartilhada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Como ele não faz parte da standard library você precisa adicionar ele no seu gopath,go mod,vendor,etc...
import "golang.org/x/sync/singleflight"
var requestGroup singleflight.Group
//para este endpoint funcionar você precisa importar o pacote singleflight e criar essa variável(eu sei global e tal, mas para este post é suficiente).
http.HandleFunc("/singleflight", func(w http.ResponseWriter, r *http.Request) {
        res, err, shared := requestGroup.Do("singleflight", func() (interface{}, error) {
            fmt.Println("calling the endpoint")
            response, err := http.Get("https://jsonplaceholder.typicode.com/photos")

            if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return nil, err
            }
            responseData, err := ioutil.ReadAll(response.Body)
            if err != nil {
                log.Fatal(err)
            }
            time.Sleep(2 * time.Second)
            return string(responseData), err
        })
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        result := res.(string)
        fmt.Println("shared = ", shared)
        fmt.Fprintf(w, "%q", result)
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vegeta novamente&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "GET http://localhost:3000/" | vegeta attack -duration=1s -rate=10 | tee results.bin | vegeta report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fi%2Fm4ynk0mhox6n2fx5cyck.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%2Fi%2Fm4ynk0mhox6n2fx5cyck.png" alt="Alt Text" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recomendo você executar o código+vegeta e ver isso executando na sua máquina.&lt;br&gt;
No primeiro endpoint, você verá que os requests são executados e o log mostra as chamadas.&lt;br&gt;
No segundo endpoint, você verá uma request, e de repente 10 true indicando que todas requests usaram a resposta compartilhada.&lt;/p&gt;

&lt;p&gt;Isso é um recurso incrível, pense em endpoints que tem um processo pesado/lento ou por serviços externos que você paga por requisições, neste último caso além de ajudar o serviço evitando processamento também poderá poupar dinheiro com requests duplicadas.&lt;br&gt;
Outro ponto é que estou usando em um serviço de http, mas poderia ser qualquer coisa, por ex. poderia ser uma consulta na base de dados , enfim cenários não faltam :).&lt;/p&gt;

&lt;p&gt;Bom é isso o que gostaria de mostrar, espero que te ajude como me ajudou saber deste package lindão e deixo meu agradecimento ao &lt;a href="https://twitter.com/henriquev" rel="noopener noreferrer"&gt;Henrique&lt;/a&gt; por te me mostrado o pacote. Vale dizer que o pacote conta com uma opção para "esquecer" a chave e tbm uma opção que o resultado é retornado via channel. Você pode por ex. definir um timeout, depois de n tempo você pode por ex. cancelar a chave ou pelo channel.&lt;/p&gt;

</description>
      <category>go</category>
      <category>performance</category>
    </item>
    <item>
      <title>Go, Google Functions and Gitlab-ci a perfect combination</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Sat, 19 Jan 2019 17:27:03 +0000</pubDate>
      <link>https://dev.to/renatosuero/go-google-functions-and-gitlab-ci-a-perfect-combination-4lao</link>
      <guid>https://dev.to/renatosuero/go-google-functions-and-gitlab-ci-a-perfect-combination-4lao</guid>
      <description>&lt;p&gt;Last week I tested google functions at &lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;gcp&lt;/a&gt; using Go, after that, I decided to add another service I like &lt;a href="https://about.gitlab.com/" rel="noopener noreferrer"&gt;gitlab&lt;/a&gt;. I liked it so much that I decided to write this post.&lt;/p&gt;

&lt;p&gt;If you know how to add an account to do a deploy at GCP or you have an account, you can ignore this section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an account to use at Gitlab.
&lt;/h2&gt;

&lt;p&gt;I'll add a lot of screenshots to make it clear.&lt;br&gt;
You need to access IAM &amp;amp; admin then Service accounts.&lt;br&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%2Fs8ujm60nyr29a8m719a5.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%2Fs8ujm60nyr29a8m719a5.png" alt="Service Account" width="800" height="756"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the button "+ CREATE SERVICE ACCOUNT"&lt;br&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%2Fd5prd8kuavlhm6yh2xid.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%2Fd5prd8kuavlhm6yh2xid.png" alt="Service Account" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type a name to identify the account&lt;br&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%2F9cpge8akbnwkcxr3gkds.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%2F9cpge8akbnwkcxr3gkds.png" alt="Service Account" width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to add 3 roles&lt;br&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%2Fo5x9wxnszfbxwivjm28q.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%2Fo5x9wxnszfbxwivjm28q.png" alt="Service Account" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a key&lt;br&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%2Fwkvatyqj71bi3sl2w9d5.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%2Fwkvatyqj71bi3sl2w9d5.png" alt="Service Account" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check that JSON is checked and click on  the create button&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/PIC%25206" 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/PIC%25206" alt="Service Account" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We finish the config at GCP, now we will add the env vars in the repository. PROJECT_ID is the project's id and SERVICE_ACCOUNT is the content you do a download when you created your key &lt;br&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%2F8ys5757q9bz07p6ftnsp.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%2F8ys5757q9bz07p6ftnsp.png" alt="Service Account" width="800" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok now we will create the code to test our deploy.I'm using the &lt;a href="https://github.com/GoogleCloudPlatform/golang-samples/tree/master/functions/helloworld" rel="noopener noreferrer"&gt;examples from Google&lt;/a&gt;&lt;br&gt;
We will create 3 files, hello_world.go that is the function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Package helloworld provides a set of Cloud Function samples.&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// HelloGet is an HTTP Cloud Function.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HelloGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&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;hello_world_test.go that is the test of the function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"io/ioutil"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http/httptest"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestHelloGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;rr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;HelloGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ReadAll: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloWorld = %q, want %q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and .gitlab-ci.yml that is the config to run the continuous integration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;image: google/cloud-sdk:alpine

test_production:
  image: golang:alpine
  stage: &lt;span class="nb"&gt;test
  &lt;/span&gt;only:
  - production
  script:
  - &lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 go &lt;span class="nb"&gt;test&lt;/span&gt; ./...

deploy_production:
  stage: deploy
  environment: Production
  only:
  - production
  script:
  - &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$SERVICE_ACCOUNT&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/&lt;span class="nv"&gt;$CI_PIPELINE_ID&lt;/span&gt;.json
  - gcloud auth activate-service-account &lt;span class="nt"&gt;--key-file&lt;/span&gt; /tmp/&lt;span class="nv"&gt;$CI_PIPELINE_ID&lt;/span&gt;.json
  - gcloud &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_ID&lt;/span&gt; functions deploy HelloGet &lt;span class="nt"&gt;--runtime&lt;/span&gt; go111 &lt;span class="nt"&gt;--trigger-http&lt;/span&gt;
  after_script:
  - &lt;span class="nb"&gt;rm&lt;/span&gt; /tmp/&lt;span class="nv"&gt;$CI_PIPELINE_ID&lt;/span&gt;.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow is, the actions will run when we merged changes in production branch. &lt;/p&gt;

&lt;p&gt;That's all, as you can see in the next screenshot, the deploy was done and the return from Google shows the URL created&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%2F3uy1zrkty1h48u25aisd.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%2F3uy1zrkty1h48u25aisd.png" alt="Service Account" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all folks, I hope it can be useful to you =). You can see the code in the &lt;a href="https://gitlab.com/renatosuero/gcp-functions-example" rel="noopener noreferrer"&gt;repository&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>serverless</category>
      <category>ci</category>
      <category>gitlab</category>
    </item>
    <item>
      <title>Go is supported in Google functions</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Thu, 17 Jan 2019 15:53:44 +0000</pubDate>
      <link>https://dev.to/renatosuero/go-is-supported-in-google-functions--2b4i</link>
      <guid>https://dev.to/renatosuero/go-is-supported-in-google-functions--2b4i</guid>
      <description>&lt;p&gt;Now we can use Go to run google functions =). Take a look an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Package helloworld provides a set of Cloud Function samples.&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"fmt"&lt;/span&gt;
        &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// HelloGet is an HTTP Cloud Function.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HelloGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&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;Deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud functions deploy HelloGet &lt;span class="nt"&gt;--runtime&lt;/span&gt; go111 &lt;span class="nt"&gt;--trigger-http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/RbnyUpVRq_4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>go</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Improve the Go code with GolangCI-Lint</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Sun, 13 Jan 2019 08:33:20 +0000</pubDate>
      <link>https://dev.to/renatosuero/improve-the-go-code-with-golangci-lint-2do6</link>
      <guid>https://dev.to/renatosuero/improve-the-go-code-with-golangci-lint-2do6</guid>
      <description>&lt;p&gt;It is a great tool to run before you send your commit to the repository(maybe you can use &lt;a href="https://dev.to/shameemreza/3-tricks-to-automate-development-tasks-with-git-hooks-2dah"&gt;git hook&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;there is another option &lt;a href="https://github.com/alecthomas/gometalinter" rel="noopener noreferrer"&gt;gometalinter&lt;/a&gt; but golangci-lint is faster than gometalinter.&lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/golangci" rel="noopener noreferrer"&gt;
        golangci
      &lt;/a&gt; / &lt;a href="https://github.com/golangci/golangci-lint" rel="noopener noreferrer"&gt;
        golangci-lint
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Fast linters runner for Go
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/golangci/golangci-lintassets/go.png"&gt;&lt;img alt="golangci-lint logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgolangci%2Fgolangci-lintassets%2Fgo.png" height="150"&gt;&lt;/a&gt;
  &lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;golangci-lint&lt;/h3&gt;

&lt;/div&gt;
  &lt;p&gt;Fast linters runner for Go&lt;/p&gt;


&lt;p&gt;&lt;code&gt;golangci-lint&lt;/code&gt; is a fast Go linters runner.&lt;/p&gt;
&lt;p&gt;It runs linters in parallel, uses caching, supports YAML configuration,
integrates with all major IDEs, and includes over a hundred linters.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install &lt;code&gt;golangci-lint&lt;/code&gt;
&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://golangci-lint.run/welcome/install/#local-installation" rel="nofollow noopener noreferrer"&gt;On my machine&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://golangci-lint.run/welcome/install/#ci-installation" rel="nofollow noopener noreferrer"&gt;On CI/CD systems&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Documentation&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Documentation is hosted at &lt;a href="https://golangci-lint.run" rel="nofollow noopener noreferrer"&gt;https://golangci-lint.run&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Social Networks&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://gophers.slack.com/archives/CS0TBRKPC" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a55b84f7a65fb9fe2e7fccae0f33aaa0d5b306dde2d2d196e45aa806a8f114e1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f536c61636b2d3432383546343f6c6f676f3d736c61636b266c6f676f436f6c6f723d7768697465" alt="Join Slack"&gt;&lt;/a&gt;
&lt;a href="https://fosstodon.org/@golangcilint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e92dd473985f15c4648cbc519763b58e67f9ea91721f4b6ab07918c66ae4e5b8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6173746f646f6e2d3633363446463f6c6f676f3d6d6173746f646f6e266c6f676f436f6c6f723d7768697465" alt="Follow on Mastodon"&gt;&lt;/a&gt;
&lt;a href="https://bsky.app/profile/golangci-lint.run" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1b397d66fda76dae5f92255b8fce85dfeedc5bd7a4a5b3ddca0ba5c8b9e27049/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f426c7565736b792d3061376166663f6c6f676f3d626c7565736b79266c6f676f436f6c6f723d7768697465" alt="Follow on Bluesky"&gt;&lt;/a&gt;
&lt;a href="https://twitter.com/golangci" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6f470bafa5924e79d4ef13306cc4587647afcfbb8a21d1be263c667a5984624d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547769747465722d3144413146323f6c6f676f3d78266c6f676f436f6c6f723d7768697465" alt="Follow on Twitter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Supporting Us&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://opencollective.com/golangci-lint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1ff2960b58780575b4208673a642fb2213be947c38f9582dc752c57892f225bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4f70656e436f6c6c6563746976652d446f6e6174652d626c75653f6c6f676f3d6f70656e636f6c6c656374697665267374796c653d666f722d7468652d6261646765" alt="Open Collective backers and sponsors"&gt;&lt;/a&gt;
&lt;a href="https://github.com/sponsors/golangci" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3474470ec24db4dd256845a56ecb90a51b7a496ecd40e03af53ffcdd713d0d6e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4769744875622d446f6e6174652d626c75653f6c6f676f3d676974687562267374796c653d666f722d7468652d6261646765" alt="GitHub Sponsors"&gt;&lt;/a&gt;
&lt;a href="https://golangci-lint.run/product/thanks/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/341347286ee9b509e935228e5deba6e9c2427ba6e0bd11c8ecc02a151b1c472d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c696e7465725f417574686f72732d446f6e6174652d626c75653f7374796c653d666f722d7468652d6261646765" alt="Linter Authors"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;golangci-lint&lt;/code&gt; is a free and open-source project built by volunteers.&lt;/p&gt;
&lt;p&gt;If you value it, consider supporting us, we appreciate it! ❤️&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Badges&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/golangci/golangci-lint/workflows/CI/badge.svg"&gt;&lt;img src="https://github.com/golangci/golangci-lint/workflows/CI/badge.svg" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/golangci/golangci-lint/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5a7a50da2f45d6f05afe8f30ac6d783052ac440063ea624af77b84a65874ab9a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f676f6c616e6763692f676f6c616e6763692d6c696e74" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://github.com/golangci/golangci-lint/releases/latest" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7a5a96f73cc6e68524ce19802889b3f3c8e940bbdf0144e139656332def25a69/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f676f6c616e6763692f676f6c616e6763692d6c696e742e737667" alt="Release"&gt;&lt;/a&gt;
&lt;a href="https://hub.docker.com/r/golangci/golangci-lint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/135e1db289ec077caad6c1b6260725aa43d6f44a662fb1763868845529859e03/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f676f6c616e6763692f676f6c616e6763692d6c696e74" alt="Docker"&gt;&lt;/a&gt;
&lt;a href="https://somsubhra.github.io/github-release-stats/?username=golangci&amp;amp;repository=golangci-lint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d2dfe3c95da9c137650ffc91baaa7ae516aa7bd58a8a72086603afbc6c95a88f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f676f6c616e6763692f676f6c616e6763692d6c696e742f746f74616c2e7376673f6c6f676f3d676974687562" alt="GitHub Releases Stats of golangci-lint"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contributors&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;This project exists thanks to all the people who contribute. &lt;a href="https://golangci-lint.run/contributing/quick-start/" rel="nofollow noopener noreferrer"&gt;How to contribute&lt;/a&gt;.&lt;/p&gt;
&lt;a href="https://github.com/golangci/golangci-lint/graphs/contributors" rel="noopener noreferrer"&gt;
  &lt;img src="https://camo.githubusercontent.com/2faf49759399515512d98b105947a800200cac9ecf4dead0aad48be909b1c06c/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f676f6c616e6763692d6c696e742f636f6e7472696275746f72732e7376673f77696474683d38393026627574746f6e3d66616c736526736b69703d676f6c616e6763696465762c434c41617373697374616e742c72656e6f766174652c666f737361626f742c676f6c616e676369626f742c6b6f7274736368616b2c676f6c616e6763692d72656c65617365722c646570656e6461626f74253542626f74253544"&gt;
&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stargazers over time&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://starchart.cc/golangci/golangci-lint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/01030578ad87b1a8e5e01af0fa0f070066c12e08c5d9015273ba5dc904112531/68747470733a2f2f7374617263686172742e63632f676f6c616e6763692f676f6c616e6763692d6c696e742e737667" alt="Stargazers over time"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/golangci/golangci-lint" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
 &lt;br&gt;&lt;br&gt;
To run the tools is pretty simple, you need to run:&lt;br&gt;&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;golangci-lint run ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to use docker, &lt;em&gt;the only thing you need to do is configure the volume to use your project path&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/github.com/golangci/golangci-lint:/go/src/github.com/golangci/golangci-lint golangci-lint run ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that's all folks, I hope it can be useful to you =) &lt;/p&gt;

</description>
      <category>go</category>
      <category>githunt</category>
    </item>
    <item>
      <title>Golang Security Checker</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Fri, 11 Jan 2019 07:31:13 +0000</pubDate>
      <link>https://dev.to/renatosuero/golang-security-checker-3j5p</link>
      <guid>https://dev.to/renatosuero/golang-security-checker-3j5p</guid>
      <description>&lt;p&gt;Gosec is a great tool to run our Go code and ensure that we have no security issues. To keep the post short, I won't explain the security issues, my focus will be to show you how to run the tool. Maybe in the future, I can write about the issues, right now if you want to understand more, please read &lt;a href="https://blog.sideci.com/lets-take-a-look-at-the-rules-of-gas-442ba286b0fe" rel="noopener noreferrer"&gt;this post&lt;/a&gt; &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/securego" rel="noopener noreferrer"&gt;
        securego
      &lt;/a&gt; / &lt;a href="https://github.com/securego/gosec" rel="noopener noreferrer"&gt;
        gosec
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Go security checker
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;gosec - Go Security Checker&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Inspects source code for security problems by scanning the Go AST and SSA code representation.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/ec0c79aa8303de74f961936a638741df09ac98096c3d8b01805881a0ac088db2/68747470733a2f2f736563757265676f2e696f2f696d672f676f7365632e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/ec0c79aa8303de74f961936a638741df09ac98096c3d8b01805881a0ac088db2/68747470733a2f2f736563757265676f2e696f2f696d672f676f7365632e706e67" width="320"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;License&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Licensed under the Apache License, Version 2.0 (the "License")
You may not use this file except in compliance with the License.
You may obtain a copy of the License &lt;a href="http://www.apache.org/licenses/LICENSE-2.0" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project status&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bestpractices.coreinfrastructure.org/projects/3218" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7ab61afdc42ca630a4fb8b3c212e2c85e1a5720829ae10f0e30fc93eba8748f2/68747470733a2f2f626573747072616374696365732e636f7265696e6672617374727563747572652e6f72672f70726f6a656374732f333231382f6261646765" alt="CII Best Practices"&gt;&lt;/a&gt;
&lt;a href="https://github.com/securego/gosec/actions?query=workflows%3ACI" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/securego/gosec/workflows/CI/badge.svg" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/securego/gosec" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d8c4330dac93d31b9b2095e54bb68058acab44d74d13170ce76082bcdcd4dad0/68747470733a2f2f636f6465636f762e696f2f67682f736563757265676f2f676f7365632f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="Coverage Status"&gt;&lt;/a&gt;
&lt;a href="https://goreportcard.com/report/github.com/securego/gosec" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3491bdde8cb1b38df88debc1534b6b354c524de6f6fd2ed955980c0f0e497105/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f736563757265676f2f676f736563" alt="GoReport"&gt;&lt;/a&gt;
&lt;a href="https://pkg.go.dev/github.com/securego/gosec/v2" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/16f1b8afc6d2e0fb890dee0799aa40180ba99990d97166c8b24f36d149ef1710/68747470733a2f2f706b672e676f2e6465762f62616467652f6769746875622e636f6d2f736563757265676f2f676f7365632f7632" alt="GoDoc"&gt;&lt;/a&gt;
&lt;a href="https://securego.io/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/49104befb925e0d6eea2d97d0708f9c97fae6aad7a693e410d4046c60828ac0d/68747470733a2f2f72656164746865646f63732e6f72672f70726f6a656374732f646f63732f62616467652f3f76657273696f6e3d6c6174657374" alt="Docs"&gt;&lt;/a&gt;
&lt;a href="https://github.com/securego/gosec/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0520a8e7fabd33abf693f52391de4416c0f9ed731e08fcbb305657f8873cc395/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f736563757265676f2f676f7365632f746f74616c2e737667" alt="Downloads"&gt;&lt;/a&gt;
&lt;a href="https://hub.docker.com/r/securego/gosec/tags" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4e756811ddce4e4f238d96ea7c897222f850518b48c5a5e4c7457dd482c7171e/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f736563757265676f2f676f7365632e737667" alt="Docker Pulls"&gt;&lt;/a&gt;
&lt;a href="http://securego.slack.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d86a78c227aed2775574dc12b4c15620d7a92bdee289bf2ede968f37428a83f6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f536c61636b2d3441313534423f7374796c653d666f722d7468652d6261646765266c6f676f3d736c61636b266c6f676f436f6c6f723d7768697465" alt="Slack"&gt;&lt;/a&gt;
&lt;a href="https://github.com/nikolaydubina/go-recipes" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnikolaydubina%2Fgo-recipes%2Fmain%2Fbadge.svg%3Fraw%3Dtrue" alt="go-recipes"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;CI Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; binary will be $(go env GOPATH)/bin/gosec&lt;/span&gt;
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh &lt;span class="pl-k"&gt;|&lt;/span&gt; sh -s -- -b &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;$(&lt;/span&gt;go env GOPATH&lt;span class="pl-pds"&gt;)&lt;/span&gt;&lt;/span&gt;/bin vX.Y.Z
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or install it into ./bin/&lt;/span&gt;
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh &lt;span class="pl-k"&gt;|&lt;/span&gt; sh -s vX.Y.Z

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; In alpine linux (as it does not come with curl by default)&lt;/span&gt;
wget -O - -q https://raw.githubusercontent.com/securego/gosec/master/install.sh &lt;span class="pl-k"&gt;|&lt;/span&gt; sh -s vX.Y.Z

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; If you want to use the checksums provided on the "Releases" page&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; then you will have to download a tar.gz file for your operating system instead of a binary file&lt;/span&gt;
wget https://github.com/securego/gosec/releases/download/vX.Y.Z/gosec_vX.Y.Z_OS.tar.gz

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; The&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/securego/gosec" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
 

&lt;p&gt;You can run the tool using a binary or using Docker. I'll show both cases to you.&lt;br&gt;
Using binary you need to run into your root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gosec &lt;span class="k"&gt;*&lt;/span&gt;.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using docker, it needs more config, but it works well. In the readme the command is &lt;em&gt;securego/gosec ./...&lt;/em&gt;, it didn't work to me, so I replaced &lt;strong&gt;./...&lt;/strong&gt; to &lt;strong&gt;projet-path&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/&amp;lt;YOUR PROJECT PATH&amp;gt;:/go/src/&amp;lt;YOUR PROJECT PATH&amp;gt; securego/gosec &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/&amp;lt;YOUR PROJECT PATH&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if you use go module, you need to use this format to run the tool.&lt;/p&gt;

&lt;p&gt;that's all folks, I hope it can be useful to you =) &lt;/p&gt;

</description>
      <category>go</category>
      <category>security</category>
      <category>githunt</category>
    </item>
    <item>
      <title>Run migrations in schemas in PostgreSQL</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Sat, 05 Jan 2019 09:37:28 +0000</pubDate>
      <link>https://dev.to/renatosuero/run-migrations-in-schemas-in-postgresql-306o</link>
      <guid>https://dev.to/renatosuero/run-migrations-in-schemas-in-postgresql-306o</guid>
      <description>&lt;p&gt;Hy everyone,&lt;/p&gt;

&lt;p&gt;This post is a continuation from that &lt;a href="https://dev.to/renatosuero/clone-schema-in-postgresql-4fpc"&gt;link&lt;/a&gt;.&lt;br&gt;
Now we have schemas, but how can we create a new table in the schemas?&lt;/p&gt;

&lt;p&gt;I've been using a function to handle migrations in the schemas, it can be used for anything. create table,changes in the table, triggers,functions,index,etc...&lt;/p&gt;

&lt;p&gt;Ok, that is the function you need to run in your database.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After that, you only need to run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select migrate_schema('your code')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select migrate_schema('CREATE TABLE DEPARTMENT(
   ID INT PRIMARY KEY      NOT NULL,
   DEPT           CHAR(50) NOT NULL,
   EMP_ID         INT      NOT NULL
);');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;A tip, you can ignore schemas, take a look in the function. In line 13 I ignore the public schema and in line 11 I ignore schemas that begin with pg_&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Another thing, I've been using the &lt;a href="https://github.com/pressly/goose" rel="noopener noreferrer"&gt;goose&lt;/a&gt; to handle my migrations. I planned to write about that, but fortunately, the &lt;a href="https://dev.to/msh5"&gt;Sho Minagawa &lt;/a&gt; wrote a great &lt;a href="https://dev.to/msh5/start-db-schema-migration-with-goose-bhg"&gt;post&lt;/a&gt;.&lt;br&gt;
We need to run more complex statements (PL/pgSQL). So, If you decide to use the tool, remember to add these lines in the migration code:&lt;/p&gt;

&lt;p&gt;-- +goose StatementBegin&lt;br&gt;
/// your statement here&lt;br&gt;
-- +goose StatementEnd&lt;/p&gt;

&lt;p&gt;When we use schemas, the goose looks for its migrations table within the schema. In my case, I want to keep my migrations table in the public schema, so I forked the project and change the instruction to check the table only in the public schema. Right now I have no plan to send a merge request, to the project, maybe it can be useful only to me. In this case, use my &lt;a href="https://github.com/renatosuero/goose" rel="noopener noreferrer"&gt;fork&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;that's all folks.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Clone schema in PostgreSQL</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Sat, 05 Jan 2019 08:45:44 +0000</pubDate>
      <link>https://dev.to/renatosuero/clone-schema-in-postgresql-4fpc</link>
      <guid>https://dev.to/renatosuero/clone-schema-in-postgresql-4fpc</guid>
      <description>&lt;p&gt;Hi everyone,&lt;/p&gt;

&lt;p&gt;My goal is to keep the post short, so If you don't know what is schema access this &lt;a href="https://www.postgresql.org/docs/11/ddl-schemas.html" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Schemas can be useful to clients, maybe a schema by the client or schema by "category". In my job(our business is based in soccer) we use schemas by championship and year.&lt;br&gt;
A sample :&lt;br&gt;
ucl_2018&lt;br&gt;
ucl_2017&lt;br&gt;
championship *that's the model&lt;/p&gt;

&lt;p&gt;Ok, now we need to create a new schema ucl_2019, right?&lt;/p&gt;

&lt;p&gt;I researched and after some time, I found a function to help me, but I needed to do changes. I didn't remember exactly what I needed to do, so I decided to share the function I've been using. Another thing this function will create everything indexes, keys, foreign keys, etc...&lt;/p&gt;

&lt;p&gt;Ok, that is the function you need to run in your database.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After that, you only need to run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select clone_schema('source','destination')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select clone_schema('championship','ucl_2019');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope it can be useful to you. I love PostgreSQL, so I want to write more about other features I like or I think that can be useful.&lt;br&gt;
&lt;del&gt;My new post will be a sequence for that, I'll show how to update the schemas, running migrations in the schemas.&lt;/del&gt; I wrote the &lt;a href="https://dev.to/renatosuero/run-migrations-in-schemas-in-postgresql-306o"&gt;post&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Generate UML diagram from a textual description</title>
      <dc:creator>Renato Suero</dc:creator>
      <pubDate>Tue, 01 Jan 2019 11:26:09 +0000</pubDate>
      <link>https://dev.to/renatosuero/generate-uml-diagram-from-a-textual-description-4e9i</link>
      <guid>https://dev.to/renatosuero/generate-uml-diagram-from-a-textual-description-4e9i</guid>
      <description>&lt;p&gt;Hi everyone,&lt;/p&gt;

&lt;p&gt;I always hated UML because every tool I saw, I needed to "draw", I feel that I'm less productive. &lt;br&gt;
So I found PlantUML and my world changed, now I could write and generate the diagram. One of the reasons I liked that option is to keep the diagrams updated, now it is simple and fast (to me).&lt;/p&gt;

&lt;p&gt;Let's see how we can use the tool.&lt;br&gt;
Firstly, another thing nice to me, I can use docker =).&lt;br&gt;
I use 2 docker images, first to generate the diagram to me. I use &lt;a href="https://hub.docker.com/r/think/plantuml/" rel="noopener noreferrer"&gt;https://hub.docker.com/r/think/plantuml/&lt;/a&gt;&lt;br&gt;
In this case, I created a file called test.uml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml
autonumber
Bob -&amp;gt; Alice : Authentication Request
Bob &amp;lt;- Alice : Authentication Response

autonumber 15
Bob -&amp;gt; Alice : Another authentication Request
Bob &amp;lt;- Alice : Another authentication Response

autonumber 40 10
Bob -&amp;gt; Alice : Yet another authentication Request
Bob &amp;lt;- Alice : Yet another authentication Response

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I run this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat test.uml | docker run --rm -i think/plantuml &amp;gt; test.svg 
cat test.uml | docker run --rm -i think/plantuml &amp;gt; test.png 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, that's the result.&lt;br&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%2F1uafttdrc1phojxnu9rv.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%2F1uafttdrc1phojxnu9rv.png" alt="Diagram generated" width="664" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another way, I run the server to write and see the diagram. I use &lt;a href="https://hub.docker.com/r/plantuml/plantuml-server/" rel="noopener noreferrer"&gt;https://hub.docker.com/r/plantuml/plantuml-server/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, I run the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -d -p 8080:8080 plantuml/plantuml-server:jetty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then, I open my browser and I access &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;. As you can see, that's the result.&lt;br&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%2Fgnzkd21n6xgvilvwm8qb.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%2Fgnzkd21n6xgvilvwm8qb.png" alt="plantUML as a server" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to play now you can use the &lt;a href="http://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa700000" rel="noopener noreferrer"&gt;official server&lt;/a&gt;, the good thing to use that server, is you can share the diagram&lt;/p&gt;

&lt;p&gt;I recommend you access the official &lt;a href="http://plantuml.com/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, my goal was to show you options to generate your diagrams and help you to be more productive.&lt;/p&gt;

&lt;p&gt;I'd like to show you a suggestion how to use dev.to using UML =)&lt;br&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%2Fk5boaak6uhjvgf0lya1u.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%2Fk5boaak6uhjvgf0lya1u.png" alt="Activity to read posts at dev.to" width="604" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd like to invite you to write/draw a diagram and share here in the comments, let's inspire others readers =)&lt;/p&gt;

</description>
      <category>uml</category>
      <category>documentation</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
