Slide 36 de 37

Atores distribuídos

Um serviço neste nó
type Note {
	Say   { text: Str }
	Count
	Total { count: Int }
}

proc tally(state: Int, msg: Note, envelope: hive.syslink.Envelope): Int {
	if msg is Note.Say(text) {
		echo text
		return state
	} else if msg is Note.Count {
		hive.syslink.answer(envelope, Note.Total(state))
		return state + 1
	}
	return state
}

proc main(): void {
	address := hive.syslink.spawn(tally, 0)
	hive.syslink.register(#Cache, address)

	async address(Note.Say("oi"))                     // dispara e esquece
	reply := address(Note.Count()) with timeout 250   // envia e espera, limitado
	if reply is Result.Ok(msg) {
		echo msg
	}
}
O mesmo serviço, verdadeiramente distribuído
type Note {
	Say     { text: Str }
	HowMany
	Counted { seen: Int }
}

proc inbox(seen: Int, note: Note, from: hive.syslink.Envelope): Int {
	if note is Note.Say(text) {
		echo "ouvi: {text}"
		return seen + 1
	} else if note is Note.HowMany {
		hive.syslink.answer(from, Note.Counted(seen))
		return seen
	}
	return seen
}

// 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
	}

	box := hive.syslink.spawn(inbox, 0)
	hive.syslink.register(#Inbox, box)

	mine := hive.syslink.at(#Inbox)
	theirs := hive.syslink.on(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}"
	}
}
hive.syslink dá a um programa serviços endereçáveis, neste processo ou em outra máquina, alcançados pela mesma instrução de qualquer forma. spawn inicia um e register o publica sob um átomo; at alcança um serviço neste nó e on alcança um em outro, ambos sem nenhum I/O. O handler de um serviço é um fold sobre sua caixa de mensagens — proc(State, Message, Envelope): State — então não há mutex em lugar nenhum: o fold é o mutex, e answer dentro dele é como uma resposta adiada é enviada. self lê o próprio endereço de um handler, monitor pede para ser avisado se outro endereço parar, e stop termina um de vez. Uma falha dentro de um serviço mata apenas aquele serviço e deixa o resto do nó rodando.listen abre este nó para outros em um endpoint — um ip:port — e node/peers dizem quem ele é e com quem mais está conectado atualmente. Dois nós não precisam de nada compartilhado além de uma chave de cluster, escrita em ~/.hive/syslink.key na primeira execução: copie esse arquivo para a segunda máquina, ou defina HIVE_SYSLINK_KEY da mesma forma nas duas, e toda conexão entre elas é TLS 1.3 de qualquer forma.