2015-11-02 2 views
1

Я довольно новичок в scala, поэтому будьте нежны!Положить будущее внутри OnFailure

Я пытаюсь создать «логическую операцию», вот пример кода:

val f1:Future[Int] = dao.insertIntoDB 
f1.flatmap{ 
    x => { 
    val f2 = sendHttpRequestFuture 
    f.onFailure{ 
     case t => dao.revertDbChangeFuture 
    } 
} 

f1.onFailure{ 
    logger.error("error) 
} 

Так что я думаю, произошло то, что внешний OnFailure будет выполняться первым, а затем внутреннюю OnFailure.

Дело в том, что onFailure return Unit, поэтому кажется странным положить будущее внутри onFailure, я не уверен, что это правильный способ справиться с таким вариантом использования.

Мне в основном нужно отменить свои изменения, а действие возврата - асинхронно.

Можете ли вы дать совет? Спасибо!

ответ

1

Play arround с этим образцом. Это показывает, как все работает. На самом деле, как я вижу, вы все исправились.

Есть две переменные, которые вы можете изменить job1Fail и job2Fail.

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

object FutFut extends App { 


    val f1: Future[Int] = Future { 
    doJob 
    } 

    val job1Fail = false 
    val job2Fail = true 

    def doJob() = { 
    if (job1Fail) sys.error("Failed to do job") else { 
     println("job 1 done") 
     1 
    } 
    } 

    def doOtherJob() { 
    if (job2Fail) sys.error("Failed to do other job") else { 
     println("other job done") 
    } 
    } 

    def revertingAll() { 
    println("reverting all") 
    } 

    f1.flatMap { 
    x => { 
     val f2 = Future { 
     doOtherJob() 
     } 
     f2.onFailure { 
     case t => revertingAll() 
     } 
     f2 
    } 
    } 

    f1.onFailure { 
    case t => println("f1 failed") 
    } 

    Thread.sleep(1000) 

} 

Таким образом, результаты следующие:

дб работа неудачу -> исходящее сообщение f1 не удалось. нет возврата.

дб работа в порядке -> плоская карта вызывается -> HTTP ошибка -> вернуться вызывается -> f1 не подведет

дб работу в порядке -> плоская карта вызывается -> HTTP ОК -> все в порядке -> нет Revert -> no fail :)

Это довольно все прецеденты.

1

Вы не должны использовать revertDbChangeFuture, потому что, как только у вас есть это будущее, это чаще всего означает, что вы уже вызвали базовое вычисление, т. Е. Вы уже возвращаете изменение БД, независимо от результата вставки. Вместо этого, вы должны добавить метод для возвращаясь изменения БД в вашем onFailure обратного вызова:

insertIntoDBFuture.onFailure { 
    case t => revertDbChange() 
} 

val f1 = insertIntoDBFuture.flatmap(sendHttpRequestFuture(_)) 
f1.onFailure{ 
    case t => logger.error("error", t) 
} 
f1 

flatMap в val f1 = insertIntoDBFuture.flatmap(sendHttpRequestFuture(_)) не будет выполнена, если insertIntoDBFuture не удается, так что вам не придется беспокоиться об этом. Вместо этого результат f1 будет таким же неудачным в будущем, поэтому вы зарегистрируете ошибку либо insertIntoDBFuture, либо sendHttpRequestFuture - или ничего, если ошибка не возникает.

+0

Я пропустил вас, я снова редактировал свой пост. Код, который я прочитал, действительно выглядит как код, который уже был вычислен. это не так. Мой вопрос был в основном о поведении будущего внутри предложения onFailure.Когда я думаю об этом немного больше, мне кажется, что при написании будущего внутри onFailure будущее будет выполнено в конце концов (даже после того, как код уже закончен). Проблема в том, что я не могу составить ее и контролировать это будущее. Например, если будущее внутри onFailure, тоже не удается, я должен добавить onFailure к нему также? И спасибо за ваш ответ! – Tomer

0

Вы, вероятно, следуешь использовать recoverWith API в этом случае, который позволяет превратить неудачное будущее с другим будущим:

f2.recoverWith({ 
    case NonFatal(_) => dao.revertDbChangeFuture 
}) 

Это вернет вам будущее против операции отмены.

Смежные вопросы