当前位置: 首页 > 面试题库 >

Scala实现这种可重试调用的方式是什么?

姚阳德
2023-03-14
问题内容

还是Scala的新手,我现在正在寻找一种在其上实现以下代码的方法:

@Override
public void store(InputStream source, String destination, long size) {

    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(size);
    final PutObjectRequest request = new PutObjectRequest(
            this.configuration.getBucket(), destination, source, metadata);

    new RetryableService(3) {

        @Override
        public void call() throws Exception {
            getClient().putObject(request);
        }
    };

}

在Scala中实现与RetryableService实现的功能相同的最佳方法是什么?

它基本上调用N次 调用
方法,如果所有方法均失败,则引发异常,如果所有方法均失败,则继续进行。这个不返回任何内容,但是我有另一个版本可以返回值(因此,我在Java中有两个类),我相信我可以在Scala中使用单个类/函数

有任何想法吗?

编辑

Java当前的实现如下:

public abstract class RetryableService {

private static final JobsLogger log = JobsLogger
        .getLogger(RetryableService.class);

private int times;

public RetryableService() {
    this(3);
}

public RetryableService(int times) {
    this.times = times;
    this.run();
}

private void run() {

    RuntimeException lastExceptionParent = null;

    int x = 0;

    for (; x < this.times; x++) {

        try {
            this.call();
            lastExceptionParent = null;
            break;
        } catch (Exception e) {
            lastExceptionParent = new RuntimeException(e);
            log.errorWithoutNotice( e, "Try %d caused exception %s", x, e.getMessage() );

            try {
                Thread.sleep( 5000 );
            } catch (InterruptedException e1) {
                log.errorWithoutNotice( e1, "Sleep inside try %d caused exception %s", x, e1.getMessage() );
            }

        }

    }

    try {
        this.ensure();
    } catch (Exception e) {
        log.error(e, "Failed while ensure inside RetryableService");
    }

    if ( lastExceptionParent != null ) {
        throw new IllegalStateException( String.format( "Failed on try %d of %s", x, this ), lastExceptionParent);
    }

}

public void ensure() throws Exception {
    // blank implementation
}

public abstract void call() throws Exception;

}

问题答案:

递归+ 一流的功能 ,按名称参数==很棒。

def retry[T](n: Int)(fn: => T): T = {
  try {
    fn
  } catch {
    case e =>
      if (n > 1) retry(n - 1)(fn)
      else throw e
  }
}

用法是这样的:

retry(3) {
  // insert code that may fail here
}

编辑
:受@themel的答案启发而略有变化。少一行代码:-)

def retry[T](n: Int)(fn: => T): T = {
  try {
    fn
  } catch {
    case e if n > 1 =>
      retry(n - 1)(fn)
  }
}

再次编辑
:递归使我感到困扰,因为它向堆栈跟踪添加了多个调用。由于某些原因,编译器无法在catch处理程序中优化尾部递归。但是,尾部递归不在catch处理程序中,可以很好地优化:-)

@annotation.tailrec
def retry[T](n: Int)(fn: => T): T = {
  val r = try { Some(fn) } catch { case e: Exception if n > 1 => None }
  r match {
    case Some(x) => x
    case None => retry(n - 1)(fn)
  }
}

再次编辑
:显然,我将把它作为一种爱好,不断回来并为此答案添加替代方法。这是一个尾递归版本,它比使用更加简单Option,但是使用return短路功能并不是惯用的Scala。

@annotation.tailrec
def retry[T](n: Int)(fn: => T): T = {
  try {
    return fn
  } catch {
    case e if n > 1 => // ignore
  }
  retry(n - 1)(fn)
}

Scala 2.10更新 。作为我的业余爱好,我偶尔会重新审视此答案。Try引入的Scala 2.10
提供了一种以尾递归方式实现重试的干净方法。

// Returning T, throwing the exception on failure
@annotation.tailrec
def retry[T](n: Int)(fn: => T): T = {
  util.Try { fn } match {
    case util.Success(x) => x
    case _ if n > 1 => retry(n - 1)(fn)
    case util.Failure(e) => throw e
  }
}

// Returning a Try[T] wrapper
@annotation.tailrec
def retry[T](n: Int)(fn: => T): util.Try[T] = {
  util.Try { fn } match {
    case util.Failure(_) if n > 1 => retry(n - 1)(fn)
    case fn => fn
  }
}


 类似资料:
  • 问题内容: 我正在研究Java标准库(6)中compare(double,double)的实现。内容为: 此实现的优点是什么? 编辑:“优点”是一个(非常)错误的单词选择。我想知道这是如何工作的。 问题答案: @Shoover的答案是正确的(阅读它!),但是它还不止于此。 由于javadoc中的规定: “此定义允许哈希表正常运行。” 假设Java设计者决定采用与包装实例相同的语义来实现。这意味着将

  • 本文向大家介绍axios为什么可以使用对象和函数两种方式调用?是如何实现的?相关面试题,主要包含被问及axios为什么可以使用对象和函数两种方式调用?是如何实现的?时的应答技巧和注意事项,需要的朋友参考一下 因为是函数。给函数上挂载了一些简写的方法,比如,等。 最后调用的都是方法。 更具体的可以查看我的这篇文章。 @若川:学习 axios 源码整体架构,打造属于自己的请求库

  • 问题内容: 我知道您不应该将显示逻辑放在控制器中,并且我正在努力使用正确的AngularJS方法来实现此目的。 我正在模态内展示表格。我正在使用Zurb Foundation的揭示模式。 标记: 控制器: 注意:$ scope.ui是我用来存储UI值的对象,在用户实际单击“添加小部件”之前,该值不应绑定到我的对象 $ scope.myobj是存储我的数据的位置。 基金会的职能提出了模式叠加。 由于

  • 我是Keras的新手,正在尝试实施解相关批次规范文件(https://arxiv.org/abs/1804.08450)作为一种学习体验。该层与标准批次规范非常相似,只包含一些附加组件。 我们现在将数据居中并应用白化变换,通过对协方差矩阵进行特征值分解来计算白化变换,而不是将输入数据集中到每个层并通过方差进行归一化。 整个过程在论文(算法1,第5页)中有明确的阐述,仅由5个等式组成,我在下面的代码

  • 想问下这种样式怎么实现

  • 在添加新的键值对时,我有几个关于重建哈希映射的问题。我将根据这些事实提出问题(它们对于Oracle JVM是正确的,不确定它们对于其他JVM是否正确): 每次当HashMap增长大于阈值(阈值=加载因子*条目数)时,Resize将重建HashMap,使其具有更大的内部表数组。新创建的条目放在哪个存储桶中并不重要,Map仍然会变得更大。即使所有条目都进入一个bucket(即它们的键“返回相同的数字)