go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/api/txn_options.go (about)

     1  // Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at:
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package api
    16  
    17  import (
    18  	"context"
    19  	"encoding/json"
    20  	"time"
    21  )
    22  
    23  type schedulerCtxKey int
    24  
    25  const (
    26  	// resyncCtxKey is a key under which *resync* txn option is stored
    27  	// into the context.
    28  	resyncCtxKey schedulerCtxKey = iota
    29  
    30  	// nonBlockingTxnCtxKey is a key under which *non-blocking* txn option is
    31  	// stored into the context.
    32  	nonBlockingTxnCtxKey
    33  
    34  	// retryCtxKey is a key under which *retry* txn option is stored into
    35  	// the context.
    36  	retryCtxKey
    37  
    38  	// revertCtxKey is a key under which *revert* txn option is stored into
    39  	// the context.
    40  	revertCtxKey
    41  
    42  	// txnDescriptionCtxKey is a key under which transaction description is stored
    43  	// into the context.
    44  	txnDescriptionCtxKey
    45  
    46  	// txnSimulationCtxKey is a key under which option enabling txn simulation
    47  	// is stored into the context.
    48  	txnSimulationCtxKey
    49  )
    50  
    51  // modifiable default parameters for the *retry* txn option
    52  var (
    53  	// DefaultRetryPeriod delays first retry by one second.
    54  	DefaultRetryPeriod = time.Second
    55  
    56  	// DefaultRetryMaxCount limits the number of retries to 3 attempts at maximum.
    57  	DefaultRetryMaxCount = 3
    58  
    59  	// DefaultRetryBackoff enables exponential back-off for retry delay.
    60  	DefaultRetryBackoff = true
    61  )
    62  
    63  /* Full-Resync */
    64  
    65  // resyncOpt represents the *resync* transaction option.
    66  type resyncOpt struct {
    67  	resyncType       ResyncType
    68  	verboseSBRefresh bool
    69  }
    70  
    71  // ResyncType is one of: Upstream, Downstream, Full.
    72  type ResyncType int
    73  
    74  const (
    75  	// NotResync is the default value for ResyncType, used when resync is actually
    76  	// not enabled.
    77  	NotResync ResyncType = iota
    78  
    79  	// FullResync resynchronizes the agent with both SB and NB.
    80  	FullResync
    81  
    82  	// UpstreamResync resynchronizes the agent with NB.
    83  	// It can be used by NB in situations when fully re-calculating the desired
    84  	// state is far easier or more efficient that to determine the minimal difference
    85  	// that needs to be applied to reach that state.
    86  	// The agent's view of SB is not refreshed, instead it is expected to be up-to-date.
    87  	UpstreamResync
    88  
    89  	// DownstreamResync resynchronizes the agent with SB.
    90  	// In this case it is assumed that the state required by NB is up-to-date
    91  	// (transaction should be empty) and only the agent's view of SB is refreshed
    92  	// and any discrepancies are acted upon.
    93  	DownstreamResync
    94  )
    95  
    96  func (t ResyncType) String() string {
    97  	switch t {
    98  	case NotResync:
    99  		return "NotResync"
   100  	case FullResync:
   101  		return "FullResync"
   102  	case UpstreamResync:
   103  		return "UpstreamResync"
   104  	case DownstreamResync:
   105  		return "DownstreamResync"
   106  	default:
   107  		return "UnknownResync"
   108  	}
   109  }
   110  
   111  var resyncType_value = map[string]int{
   112  	"NotResync":        int(NotResync),
   113  	"FullResync":       int(FullResync),
   114  	"UpstreamResync":   int(UpstreamResync),
   115  	"DownstreamResync": int(DownstreamResync),
   116  }
   117  
   118  func (t ResyncType) MarshalJSON() ([]byte, error) {
   119  	return json.Marshal(t.String())
   120  }
   121  
   122  func (t *ResyncType) UnmarshalJSON(b []byte) error {
   123  	if b[0] == '"' {
   124  		var s string
   125  		if err := json.Unmarshal(b, &s); err != nil {
   126  			return err
   127  		}
   128  		if v, ok := resyncType_value[s]; ok {
   129  			*t = ResyncType(v)
   130  		} else {
   131  			*t = NotResync
   132  		}
   133  	} else {
   134  		var n int
   135  		if err := json.Unmarshal(b, &n); err != nil {
   136  			return err
   137  		}
   138  		*t = ResyncType(n)
   139  	}
   140  	return nil
   141  }
   142  
   143  // WithResync prepares context for transaction that, based on the resync type,
   144  // will trigger resync between the configuration states of NB, the agent and SB.
   145  // For DownstreamResync the transaction should be empty, otherwise it should
   146  // carry non-NIL values - existing NB values not included in the transaction
   147  // are automatically removed.
   148  // When <verboseSBRefresh> is enabled, the refreshed state of SB will be printed
   149  // into stdout. The argument is irrelevant for UpstreamResync, where SB state is
   150  // not refreshed.
   151  func WithResync(ctx context.Context, resyncType ResyncType, verboseSBRefresh bool) context.Context {
   152  	return context.WithValue(ctx, resyncCtxKey, &resyncOpt{
   153  		resyncType:       resyncType,
   154  		verboseSBRefresh: verboseSBRefresh,
   155  	})
   156  }
   157  
   158  // IsResync returns true if the transaction context is configured to trigger resync.
   159  func IsResync(ctx context.Context) (resyncType ResyncType, verboseSBRefresh bool) {
   160  	resyncArgs, isResync := ctx.Value(resyncCtxKey).(*resyncOpt)
   161  	if !isResync {
   162  		return NotResync, false
   163  	}
   164  	return resyncArgs.resyncType, resyncArgs.verboseSBRefresh
   165  }
   166  
   167  /* Non-blocking Txn */
   168  
   169  // nonBlockingTxnOpt represents the *non-blocking* transaction option.
   170  type nonBlockingTxnOpt struct {
   171  	// no attributes
   172  }
   173  
   174  // WithoutBlocking prepares context for transaction that should be scheduled
   175  // for execution without blocking the caller of the Commit() method.
   176  // By default, commit is blocking.
   177  func WithoutBlocking(ctx context.Context) context.Context {
   178  	return context.WithValue(ctx, nonBlockingTxnCtxKey, &nonBlockingTxnOpt{})
   179  }
   180  
   181  // IsNonBlockingTxn returns true if transaction context is configured for
   182  // non-blocking Commit.
   183  func IsNonBlockingTxn(ctx context.Context) bool {
   184  	_, nonBlocking := ctx.Value(nonBlockingTxnCtxKey).(*nonBlockingTxnOpt)
   185  	return nonBlocking
   186  }
   187  
   188  /* Retry */
   189  
   190  // RetryOpt represents the *retry* transaction option.
   191  type RetryOpt struct {
   192  	Period     time.Duration
   193  	MaxCount   int
   194  	ExpBackoff bool
   195  }
   196  
   197  // WithRetry prepares context for transaction for which the scheduler will retry
   198  // any (retriable) failed operations after given <period>. If <expBackoff>
   199  // is enabled, every failed retry will double the next delay. Non-zero <maxCount>
   200  // limits the maximum number of retries the scheduler will execute.
   201  // Can be combined with revert - even failed revert operations will be re-tried.
   202  // By default, the scheduler will not automatically retry failed operations.
   203  func WithRetry(ctx context.Context, period time.Duration, maxCount int, expBackoff bool) context.Context {
   204  	return context.WithValue(ctx, retryCtxKey, &RetryOpt{
   205  		Period:     period,
   206  		MaxCount:   maxCount,
   207  		ExpBackoff: expBackoff,
   208  	})
   209  }
   210  
   211  // WithRetryDefault is a specialization of WithRetry, where retry parameters
   212  // are set to default values.
   213  func WithRetryDefault(ctx context.Context) context.Context {
   214  	return context.WithValue(ctx, retryCtxKey, &RetryOpt{
   215  		Period:     DefaultRetryPeriod,
   216  		MaxCount:   DefaultRetryMaxCount,
   217  		ExpBackoff: DefaultRetryBackoff,
   218  	})
   219  }
   220  
   221  // WithRetryMaxCount is a specialization of WithRetry, where <period> and <expBackoff>
   222  // are set to default values and the maximum number of retries can be customized.
   223  func WithRetryMaxCount(ctx context.Context, maxCount int) context.Context {
   224  	return context.WithValue(ctx, retryCtxKey, &RetryOpt{
   225  		Period:     DefaultRetryPeriod,
   226  		MaxCount:   maxCount,
   227  		ExpBackoff: DefaultRetryBackoff,
   228  	})
   229  }
   230  
   231  // IsWithRetry returns true if transaction context is configured to allow retry,
   232  // including the option parameters, or nil if retry is not enabled.
   233  func IsWithRetry(ctx context.Context) (retryArgs *RetryOpt, withRetry bool) {
   234  	retryArgs, withRetry = ctx.Value(retryCtxKey).(*RetryOpt)
   235  	return
   236  }
   237  
   238  /* Revert */
   239  
   240  // revertOpt represents the *revert* transaction option.
   241  type revertOpt struct {
   242  	// no attributes
   243  }
   244  
   245  // WithRevert prepares context for transaction that will be reverted if any
   246  // of its operations fails.
   247  // By default, the scheduler executes transactions in a best-effort mode - even
   248  // in the case of an error it will keep the effects of successful operations.
   249  func WithRevert(ctx context.Context) context.Context {
   250  	return context.WithValue(ctx, revertCtxKey, &revertOpt{})
   251  }
   252  
   253  // IsWithRevert returns true if the transaction context is configured
   254  // to revert transaction if any of its operations fails.
   255  func IsWithRevert(ctx context.Context) bool {
   256  	_, isWithRevert := ctx.Value(revertCtxKey).(*revertOpt)
   257  	return isWithRevert
   258  }
   259  
   260  /* Txn Description */
   261  
   262  // txnDescriptionOpt represents the *txn-description* transaction option.
   263  type txnDescriptionOpt struct {
   264  	description string
   265  }
   266  
   267  // WithDescription prepares context for transaction that will have description
   268  // provided.
   269  // By default, transactions are without description.
   270  func WithDescription(ctx context.Context, description string) context.Context {
   271  	return context.WithValue(ctx, txnDescriptionCtxKey, &txnDescriptionOpt{description: description})
   272  }
   273  
   274  // IsWithDescription returns true if the transaction context is configured
   275  // to include transaction description.
   276  func IsWithDescription(ctx context.Context) (description string, withDescription bool) {
   277  	descriptionOpt, withDescription := ctx.Value(txnDescriptionCtxKey).(*txnDescriptionOpt)
   278  	if !withDescription {
   279  		return "", false
   280  	}
   281  	return descriptionOpt.description, true
   282  }
   283  
   284  /* Txn Simulation */
   285  
   286  // txnSimulationOpt represents the *txn-simulation* transaction option.
   287  type txnSimulationOpt struct {
   288  	// no attributes
   289  }
   290  
   291  // WithSimulation enables simulation of txn operations, which is triggered before
   292  // execution to obtain the sequence of intended operations without actually
   293  // calling any CRUD operations and assuming no failures.
   294  // By default, simulation is disabled.
   295  func WithSimulation(ctx context.Context) context.Context {
   296  	return context.WithValue(ctx, txnSimulationCtxKey, &txnSimulationOpt{})
   297  }
   298  
   299  // IsWithSimulation returns true if transaction context is configured to enable
   300  // pre-execution simulation.
   301  func IsWithSimulation(ctx context.Context) bool {
   302  	_, withSimulation := ctx.Value(txnSimulationCtxKey).(*txnSimulationOpt)
   303  	return withSimulation
   304  }