Slide 59 de 74

Serviços entre nós

O mesmo serviço, verdadeiramente distribuído
type Note {
	Say     { text: Str }
	HowMany
	Counted { seen: Int }
}

proc inbox(seen: mut Int, note: Note): Note {
	if note is Note.Say(text) {
		echo "ouvi: {text}"
		seen += 1
		return note
	} else if note is Note.HowMany {
		return Note.Counted(seen)
	} else if note is Note.Counted(_) {
		return note
	}
}

// Rode este mesmo programa em duas máquinas: um nó é identificado por onde
// ele está, então nada nos dois processos difere além dos endereços digitados
// abaixo — 192.168.1.10:9100 e 192.168.1.11:9100, um de cada lado.
proc main(): void {
	echo "O ip:port deste nó?"
	me := hive.term.read()
	echo "O ip:port do outro nó?"
	peer := hive.term.read()

	if hive.syslink.listen(me) is Result.Error(err) {
		panic err
	}

	if spawn(inbox, 0, #Inbox) is Result.Error(err) {
		panic err
	}

	mine := at(#Inbox)
	theirs := at(peer, #Inbox)

	async theirs(Note.Say("olá de {me}"))
	hive.task.sleep(500)
	echo "peers conectados: {len(hive.syslink.peers())}"

	if theirs(Note.HowMany()) with timeout 4000 is Result.Ok(reply) {
		echo "o outro nó respondeu: {reply}"
	}
}

O que o hive.syslink guarda é o próprio nó. Um nó não tem nome: ele é identificado pelo endpoint em que pode ser alcançado, então uma lista de pares é um dado comum de tempo de execução.

  • listen(endpoint) abre este nó para os outros e responde com o endpoint que um par deve usar — uma porta 0 pede ao sistema que escolha uma, e a resposta a carrega. O host é anunciado como foi escrito, já que o endereço pelo qual esta máquina é alcançada é o programa quem diz, com hive.net.localAddress(). A porta é aberta em todas as interfaces, exceto que um host de loopback abre só o loopback.
  • node() é o endpoint deste nó, "" antes de ele escutar, e peers() os nós a que ele está conectado agora.
  • Um nó precisa de listen antes de alcançar outro: até lá um pedido responde "NoListener".

Dois nós não precisam compartilhar nada além de uma chave de cluster, escrita em ~/.hive/syslink.key na primeira execução: copie esse arquivo para a outra máquina, defina HIVE_SYSLINK_KEY igual nas duas, ou faça cada programa chamar hive.syslink.setKey(key) com um Secret — uma chave só daquele programa, guardada na memória e nunca escrita no arquivo nem no ambiente, e usada em toda conexão aberta ou aceita depois da chamada. Toda conexão entre dois nós é TLS 1.3, com autenticação mútua. Existe uma conexão persistente por par de nós, aberta no primeiro uso, então as mensagens entre dois nós chegam na ordem em que foram enviadas. Elas atravessam como JSON, pelos mesmos codecs que o hive.json deriva — então as anotações JSON as de um tipo de mensagem moldam o fio também, e um mapa não pode viajar — com um resumo do tipo da mensagem ao lado de cada uma, então um nó construído com outra declaração falha alto em vez de ler os bytes de outro tipo. A entrega é de melhor esforço: mensagens enfileiradas para um nó dado como caído são descartadas.