github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/pkg/publisher/combo/fallback.go (about)

     1  package combo
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/filecoin-project/bacalhau/pkg/model"
     7  	"github.com/filecoin-project/bacalhau/pkg/publisher"
     8  	"github.com/rs/zerolog/log"
     9  	"go.uber.org/multierr"
    10  )
    11  
    12  type fallbackPublisher struct {
    13  	publishers []publisher.Publisher
    14  }
    15  
    16  // NewFallbackPublisher returns a publisher.Publisher that will try multiple other
    17  // Publishers in order until one succeeds.
    18  //
    19  // The Publishers are tried in the order specified in the call to
    20  // NewFallbackPublisher. If and only if all the Publishers return an error
    21  // result, the fallback publisher will also return an error result. Otherwise,
    22  // it will return the result of the first Publisher to succeed and will swallow
    23  // any errors. Subsequent Publishers will not be attempted after one succeeds.
    24  func NewFallbackPublisher(publishers ...publisher.Publisher) publisher.Publisher {
    25  	return &fallbackPublisher{
    26  		publishers: publishers,
    27  	}
    28  }
    29  
    30  // fallback accepts a slice of publisher objects and passes them to the supplied
    31  // function in order, until one does not return an error value and then returns
    32  // that result. If all publishers return an error value, a composite error is
    33  // returned.
    34  func fallback[T any, P any](ctx context.Context, publishers []P, method func(P) (T, error)) (T, error) {
    35  	var anyErr error
    36  	for _, publisher := range publishers {
    37  		result, err := method(publisher)
    38  		if err == nil {
    39  			return result, nil
    40  		} else {
    41  			log.Ctx(ctx).Warn().Msgf("publisher %v returned an error: %s", publisher, err.Error())
    42  			anyErr = multierr.Append(anyErr, err)
    43  		}
    44  	}
    45  
    46  	var zeroResult T
    47  	return zeroResult, anyErr
    48  }
    49  
    50  // IsInstalled implements publisher.Publisher
    51  func (f *fallbackPublisher) IsInstalled(ctx context.Context) (bool, error) {
    52  	return fallback(ctx, f.publishers, func(p publisher.Publisher) (bool, error) {
    53  		return p.IsInstalled(ctx)
    54  	})
    55  }
    56  
    57  // PublishShardResult implements publisher.Publisher
    58  func (f *fallbackPublisher) PublishShardResult(
    59  	ctx context.Context,
    60  	shard model.JobShard,
    61  	hostID string,
    62  	shardResultPath string,
    63  ) (model.StorageSpec, error) {
    64  	return fallback(ctx, f.publishers, func(p publisher.Publisher) (model.StorageSpec, error) {
    65  		return p.PublishShardResult(ctx, shard, hostID, shardResultPath)
    66  	})
    67  }