Beispiel #1
0
func SetService(service *core.Service) error {
	// in case of failure
	oldServices, err := database.GetServices()
	if err != nil {
		return err
	}

	// apply to balancer
	err = balance.SetService(service)
	if err != nil {
		return err
	}

	if !database.CentralStore {
		// save to backend
		err = database.SetService(service)
		if err != nil {
			// undo balancer action
			if uerr := balance.SetServices(oldServices); uerr != nil {
				err = fmt.Errorf("%v - %v", err.Error(), uerr.Error())
			}
			return err
		}
	}
	return nil
}
Beispiel #2
0
func TestGetServices(t *testing.T) {
	services, err := database.GetServices()
	if err != nil {
		t.Errorf("Failed to GET services - %v", err)
	}

	if services[0].Id != testService2.Id {
		t.Errorf("Read service differs from written service")
	}
}
Beispiel #3
0
func TestNoneGetServices(t *testing.T) {
	// don't use cluster.GetServices()
	services, err := database.GetServices()
	if err != nil {
		t.Errorf("Failed to GET services - %v", err)
		t.FailNow()
	}

	if services[0].Id != testService2.Id {
		t.Errorf("Read service differs from written service")
	}
}
Beispiel #4
0
// GetServices gets a list of services from the database, or another cluster member.
func (r *Redis) GetServices() ([]core.Service, error) {
	if database.CentralStore {
		return database.GetServices()
	}

	conn := pool.Get()
	defer conn.Close()

	// get known members(other than me) to 'poll' for services
	members, _ := redis.Strings(conn.Do("SMEMBERS", "members"))
	if len(members) == 0 {
		// should only happen on new cluster
		// assume i'm ok to be master so don't reset imported services
		config.Log.Trace("[cluster] - Assuming OK to be master, using services from my database...")
		return common.GetServices()
	}
	for i := range members {
		if members[i] == self {
			// if i'm in the list of members, new requests should have failed while `waitForMembers`ing
			config.Log.Trace("[cluster] - Assuming I was in sync, using services from my database...")
			return common.GetServices()
		}
	}

	c, err := redis.DialURL(config.ClusterConnection, redis.DialConnectTimeout(15*time.Second), redis.DialPassword(config.ClusterToken))
	if err != nil {
		return nil, fmt.Errorf("Failed to reach redis for services subscriber - %v", err)
	}
	defer c.Close()

	message := make(chan interface{})
	subconn := redis.PubSubConn{c}

	// subscribe to channel that services will be published on
	if err := subconn.Subscribe("services"); err != nil {
		return nil, fmt.Errorf("Failed to reach redis for services subscriber - %v", err)
	}
	defer subconn.Close()

	// listen always
	go func() {
		for {
			message <- subconn.Receive()
		}
	}()

	// todo: maybe use ttl?
	// timeout is how long to wait for the listed members to come back online
	timeout := time.After(time.Duration(20) * time.Second)

	// loop attempts for timeout, allows last dead members to start back up
	for {
		select {
		case <-timeout:
			return nil, fmt.Errorf("Timed out waiting for services from %v", strings.Join(members, ", "))
		default:
			// request services from each member until successful
			for _, member := range members {
				// memberTimeout is how long to wait for a member to respond with list of services
				memberTimeout := time.After(3 * time.Second)

				// ask a member for its services
				config.Log.Trace("[cluster] - Attempting to request services from %v...", member)
				_, err := conn.Do("PUBLISH", "portal", fmt.Sprintf("get-services %s", member))
				if err != nil {
					return nil, err
				}

				// wait for member to respond
				for {
					select {
					case <-memberTimeout:
						config.Log.Debug("[cluster] - Timed out waiting for services from %v", member)
						goto nextMember
					case msg := <-message:
						switch v := msg.(type) {
						case redis.Message:
							config.Log.Trace("[cluster] - Received message on 'services' channel")
							services, err := marshalSvcs(v.Data)
							if err != nil {
								return nil, fmt.Errorf("Failed to marshal services - %v", err.Error())
							}
							config.Log.Trace("[cluster] - Services from cluster: %#v\n", *services)
							return *services, nil
						case error:
							return nil, fmt.Errorf("Subscriber failed to receive services - %v", v.Error())
						}
					}
				}
			nextMember:
			}
		}
	}
}
Beispiel #5
0
func GetServices() ([]core.Service, error) {
	return database.GetServices()
}