Skip to content

Instantly share code, notes, and snippets.

@Cristopheer96
Created December 16, 2024 21:08
Show Gist options
  • Save Cristopheer96/52ab2c0fb9e5a42bb6eb7f6622cdc774 to your computer and use it in GitHub Desktop.
Save Cristopheer96/52ab2c0fb9e5a42bb6eb7f6622cdc774 to your computer and use it in GitHub Desktop.
# Características:
# Cada nodo tiene un ID único --LISTO
# Mantiene una lista de vecinos (otros nodos) --LISTO
# Tiene un log interno de eventos y estados --LSITO
# - Puede proponer un estado y buscar consenso a través de un algoritmo simplificado
# - Puede simular particiones de red y fallos --LISTO
# - Puede registrar todos los mensajes y transiciones de estado LSITO
class Node
attr_reader :id, :log
def initialize(id)
@id = id
@neighbors = []
@log = []
@partitioned_nodes = []
@failed = false
@current_value = nil
@proposed_value = nil
# Almacén simple para guardar votos y propuestas,
@received_votes = {}
@highest_proposal_value_accepted = 0 # almacenamos el mayor valor previamente aceptado
end
def add_neighbor(node)
@neighbors << node
log_event("Nodo #{@id} agregó como vecino al nodo #{node.id} siendo las #{Time.now.strftime('%H:%M:%S')}")
end
# TRIGGER PARA INICIAR UN NUEVO CONSENSO
def propose_state(value)
return if @failed
@proposed_value = value
log_event("Nodo #{@id} propone estado: #{value} siendo las #{Time.now.strftime('%H:%M:%S')}")
send_proposal_to_neighbors(value)
end
def send_proposal_to_neighbors(value)
@received_votes = { accepted: 0, rejected: 0 }
@neighbors.each do |neighbor|
next if partitioned?(neighbor) || neighbor.failed? #Ignoramos a los que no tenemos comunicacion y los que estan Apagados
neighbor.receive_proposal(@id, value)
end
check_consensus
end
def receive_proposal(from_id, value)
return if @failed
#LOGICA MADRE: Aceptar esta propuesta si el candidato es mayor o igual a cualquier propuesta aceptada previamente(@highest_proposal_value_accepted).
if value >= @highest_proposal_value_accepted
# Actualizar el número de propuesta y el valor aceptado
log_event("Nodo #{@id} acepta la propuesta Nodo #{from_id} con valor: #{value} siendo las #{Time.now.strftime('%H:%M:%S')}")
send_vote_to_node(from_id, :accepted, value)
else
log_event("Nodo #{@id} rechaza la propuesta Nodo #{from_id} con valor: #{value} siendo las #{Time.now.strftime('%H:%M:%S')}")
send_vote_to_node(from_id, :rejected, value)
end
end
def send_vote_to_node(to_id, status, value)
log_event("Nodo #{@id} envía voto (#{status}) a Nodo #{to_id} por el valor: #{value}")
node = @neighbors.find{ |n| n.id == to_id } #poddemos pasralor apra un metodo
return if node.nil? || partitioned?(node) || node.failed?
node.receive_vote(@id, status, value)
end
# Recibir voto de un vecino
def receive_vote(from_id, status, value)
return if @failed
log_event("Nodo #{@id} recibió voto (#{status}) desde Nodo #{from_id} por el valor: #{value}")
if status == :accepted
@received_votes[:accepted] += 1
else
@received_votes[:rejected] += 1
end
end
def check_consensus
return if @proposed_value.nil?
total_neighbors = @neighbors.size
votes_for = @received_votes[:accepted]
#Mayoria simple la mitad +1
if votes_for > total_neighbors / 2.0
@current_value = @proposed_value if @current_value.nil? || @proposed_value > @current_value
log_event("Nodo #{@id} alcanzó consenso en el valor: #{@current_value}")
@proposed_value = nil
else
log_event("Nodo #{@id}: no se logró consenso para el valor propuesto #{@proposed_value}")
@proposed_value = nil
end
end
def simulate_partition(nodes_array)
return if @failed
@partitioned_nodes = nodes_array.map(&:id)
log_event("Nodo #{@id} simula partición con nodos: #{@partitioned_nodes.join(', ')}")
end
def retrieve_log
"Log del Nodo #{@id}:\n" + @log.join("\n")
end
def failed?
@failed
end
private
def log_event(event)
@log << "[#{Time.now.strftime('%H:%M:%S')}] #{event}"
end
def partitioned?(node)
@partitioned_nodes.include?(node.id)
end
end
node1 = Node.new(1)
node2 = Node.new(2)
node3 = Node.new(3)
node4 = Node.new(4)
# Conectamos nodoss
node1.add_neighbor(node2)
node1.add_neighbor(node3)
node2.add_neighbor(node1)
node2.add_neighbor(node3)
node3.add_neighbor(node1)
node3.add_neighbor(node2)
# Proponer estados
node1.propose_state(1)
node2.propose_state(2)
node3.simulate_partition([node1])
node2.propose_state(3)
# Logss
puts node1.retrieve_log
puts node2.retrieve_log
puts node3.retrieve_log
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment