Diário

Estas são as entradas do meu diário, onde compartilho pensamentos, ideias e reflexões do dia a dia. Você pode encontrar uma variedade de tópicos, desde experiências pessoais até observações sobre o mundo ao meu redor. Sinta-se à vontade para explorar e acompanhar minhas jornadas digitais.

Para gerar o diário, eu criei o aplicativo jnl que é um gerador de diário pessoal. E exportei as entradas marcadas com a tag public para o site.

Redirecionando a saída do terminal.

Você pode redirecionar toda a saída de um script para um arquivo usando um único comando no início do script.

Nesse exemplo, a saída do comando ls será direcionada para o arquivo out.txt.

#!/bin/bash
exec >out.txt 2>&1
ls -al --color

Você também pode redirecionar a saída para o console, usando /dev/console, requer permissão de root.

#!/bin/bash
exec >/dev/console 2>&1
ls -al --color

O parâmetro --color é usado para manter a saída colorida, porque o comando ls detecta se a saída é um terminal ou não, e ajusta a saída de acordo.


Baytimetro

Esse fim de semana fiz algumas brincadeiras com o terminal, desenhando direto e recriei um recurso lá dos anos 80 que, apesar de extremamente simples, é muito útil: o baytimetro.

echo "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
echo "         1         2         3         4         5         6         7         8"

Ótimo chamar com seu desenho de tela e descobrir se você precisa colocar algum caractere mais para a direita ou esquerda.

É ridiculamente simples, mas fazer esse tipo de coisa tem um apelo nostálgico muito grande para mim.


Função toclip

Esta é uma função Bash que uso como parte de meus scripts e ambientes de desenvolvimento. Ela copia o conteúdo do stdin para a área de transferência. Muito útil quando você está acessando um servidor via SSH.

toclip() {
    [[ ${SSH_CONNECTION-}${SSH_TTY-} ]] && {
        printf $'\033]52;c;%s\a' "$(base64 -w0 2>/dev/null || base64 | tr -d '\n')"
        return
    }

    case $OSTYPE in
        darwin*) pbcopy ;;
        linux*)
            #command -v wl-copy >/dev/null 2>&1 && wl-copy && return
            command -v xclip   >/dev/null 2>&1 && xclip -selection clipboard && return
            # Fallback Linux without xclip or wl-copy returns to OSC52
            printf $'\033]52;c;%s\a' "$(base64 -w0 2>/dev/null || base64 | tr -d '\n')"
            ;;
    esac
}

Exemplo de uso

Direto do stdin:

echo "Texto para copiar" | toclip

Copiando o conteúdo de um arquivo:

toclip < arquivo.txt

Listando servidores DNS

Para listar os servidores DNS usados no macOS:

scutil --dns

Útil para saber quais servidores foram pegos depois de renovar o DHCP.


Não largue o osso

Uma vez, meu tio William me contou uma história de um piloto de corrida que estava com ele e ia passar por uma curva com uma leve subida. Enquanto tangenciava a curva perfeitamente, em um único e contínuo movimento, reduziu a marcha e acelerou, ao mesmo tempo, virou a fita no toca-fitas. Sem trancos, com o carro ganhando somente a potência necessária. Fez tudo isso como se não fosse nada, enquanto conversava.

Meu tio usou essa história para me falar sobre preparo e sobre conhecer bem sua profissão. Essa habilidade não vem do nada, não é inata; vem de trabalho duro e determinação.

Para quem está lendo isso hoje, várias décadas depois, é difícil explicar a complexidade dessa manobra, naquele tempo de câmbios manuais e carburadores mecânicos. Principalmente se você não souber operar um toca-fitas.

Sinto falta dessas conversas com ele. Gostaria de ter assistido a mais corridas ao seu lado.

Nas palavras do Sr. William: – Não largue o osso.


n8n com padman

Tenho uma máquina que só tem uma regra: tudo que for executado nela deve ser feito em um container.

# podman volume create n8n_data 2>/dev/null || true
podman run -it --rm \
  --name n8n \
  -p 5678:5678 \
  -v n8n_data:/home/node/.n8n \
  -e N8N_RUNNERS_ENABLED=true \
  -e N8N_SECURE_COOKIE=false \
  -e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true \
  docker.n8n.io/n8nio/n8n

Ajustes para rodar o n8n na rede interna

Essas configurações são para rede interna, maquina não acessível pela internet, sem SSL. Use apenas em ambiente de desenvolvimento ou teste.

Diminui as permissões do arquivo de configuração do n8n.

chmod 600 /home/user/.n8n/config

Rodando na rede interna sem SSL e com task runners habilitados:

export N8N_RUNNERS_ENABLED=true #enable task runners
export N8N_SECURE_COOKIE=false #disable secure cookies
npx n8n

Listar variáveis

Tecnica para fazer “debug de pobre” em Lua, listando variáveis globais e locais.

-- List all global variables
for name, value in pairs(_G) do
    local repr = tostring(value)
    print(string.format("%s = %s", name, repr))
end
-- List all local variables in the current function
-- This will only work if the code is run in a function context
local function list_locals()
    local i = 1
    while true do
        local var_name, var_value = debug.getlocal(2, i)
        if not var_name then break end
        print(string.format("%s = %s", var_name, tostring(var_value)))
        i = i + 1
    end
end

-- Example
local function demo()
    local a = 10
    local b = "hello"
    list_locals()  -- This will list local variables a and b
end

demo()


Sobre tentar manter um diário: Se eu não escrever o que tenho na cabeça imediatamente, provavelmente eu nunca vou escrever.


Processamento de Registros em Lote com PostgreSQL e Go

Este é um padrão interessante para processamento de registros em lote no Go com PostgreSQL. Ele utiliza transações e bloqueios para garantir que os registros sejam processados de forma segura e eficiente, evitando conflito entre múltiplas instâncias do processo.

O truque é combinar o uso de FOR UPDATE SKIP LOCKED para evitar que múltiplas instâncias do processo leiam e processem o mesmo registro ao mesmo tempo, e o uso do índice (id) para evitar que algum erro de processamento faça com que o registro seja processado novamente porque não houve uma mudança de status.

Se houver um erro durante o processamento, o registro não é atualizado e permanece com o status ‘pendente’. Sem o WHERE id > $1, o loop poderia entrar em um ciclo infinito tentando processar o mesmo registro repetidamente.

	var id int
	for {
		done := func() bool {

			const sqlStatement = `SELECT
                id, ...
            FROM ...
            WHERE id > $1
            AND status = 'pendente'
            AND ...
            ORDER BY id
            FOR UPDATE SKIP LOCKED LIMIT 1;`

            // aqui inicia uma transação
            tx := ...
            defer func() {
                // mecanismo de rollback
            }()

            // então executa a consulta
            err := tx.QueryRow(sqlStatement, id).Scan(&id, ...)
            if err != nil {
                if errors.Is(err, sql.ErrNoRows) {
                    return true // não há mais registros
                }
                // trata outros erros
                ...
                return false
            }

            // aqui faz o processamento do registro e atualiza o status
            // pode ser fail, paid, processed, etc.
            // ...

            // se tudo estiver ok, confirma a transação
            err = tx.Commit()
            if err != nil {
                // trata erro de commit geralmente log.Fatal(...)
            }
            return false // indica que o loop deve continuar
        }()
        if done {
            break // não há mais registros para processar
        }
    }

Este é um exemplo bom para processamento de registros em lote e pode ser tranquilamente colocado para rodar de tempos em tempos, como um cron job, para processar registros pendentes em um banco de dados PostgreSQL.

Uma vantagem interessante é que, se o processamento demorar muito, automaticamente o cron vai carregar outras instâncias do processo, que vão pegar os registros que ainda não foram processados e não estão bloqueados (SKIP LOCKED). Isso permite que o sistema escale horizontalmente, processando mais registros em paralelo sem risco de conflitos.