Skip to content

Instantly share code, notes, and snippets.

@DhavalDalal
Last active April 24, 2019 14:17
Show Gist options
  • Save DhavalDalal/bb62cf748f193a7cc051811cb23d1af6 to your computer and use it in GitHub Desktop.
Save DhavalDalal/bb62cf748f193a7cc051811cb23d1af6 to your computer and use it in GitHub Desktop.

SMS and Email Notification (Scala)

Notification.scala contains all the necessary implementations and a couple of missing ones. Using Scala's Futures implement the problem parts below:

  • Part 1

    • Send notification for debit or credit transactions on a customer’s bank account.
    • Implement either credit or debit operation.
    • You must send both the messages SMS and Email upon a successful transaction.
  • Part 2

    • Retry any service method - sendSms or sendEmail until a specified number of times.
    • Hint: For this write a generic retry method which consumes a CBN Future and returns a Future that succeeds or fails.
    • Enhance the above to now retry after every specified duration.
    • You can use the enableSMSAfter or enableEmailAfter methods on NotificationService to test.
  • Part 3

    • Using the earlier retry (from Part 2) caused multiple SMS’ and Email’s being sent, despite the success of intermediate future.
    • Change the behaviour of retry such that:
      • if any of the intermediate future succeeds, it stops retrying and exits.
      • if none of the futures succeeds, it retries until the specified number of times every specified duration
    • Finally, use it the AccountService’s debit or credit implementation to see it in action.
case class Message(from: String, to: String, subject: String, text: String)
case object NotificationService {
private var enableSmsAfter: Int = 0
private var enableEmailAfter: Int = 0
def enableSendSmsAfter(howMany: Int) = enableSmsAfter = howMany
def enableSendEmailAfter(howMany: Int) = enableEmailAfter = howMany
def sendSms(message: Message): Unit = {
println(s"Sending SMS to ${message.to}, message = ${message.text}")
Thread.sleep(400)
if (enableSmsAfter > 0) {
enableSmsAfter -= 1
println("SMS Service Down!")
throw new Error("SMS Service Down!")
}
else println(s"Sent SMS to ${message.to}")
}
def sendEmail(message: Message): Unit = {
println(s"Sending Email to ${message.to}, message = ${message.text}")
Thread.sleep(200)
if (enableEmailAfter > 0) {
enableEmailAfter -= 1
println("Email Service Down!")
throw new Error("Email Service Down!")
}
else println(s"Sent Email to ${message.to}")
}
}
type Customer = String
case class Account(id: Int = 0, balance: Double, customer: Customer) {
def credit(amount: Double) = copy(balance = balance + amount)
def debit(amount: Double) = copy(balance = balance - amount)
}
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
case object AccountRepository {
import scala.collection.mutable.Map
private val accounts = Map(1 -> Account(1, 1000, "[email protected]"),
2 -> Account(2, 5000, "[email protected]"))
def findById(id: Int): Future[Account] = Future(accounts(id))
def saveOrUpdate(account: Account): Future[Account] = Future {
val id = account.id
if (account.id == 0) {
val newId = accounts.keys.max + 1
Thread.sleep(300)
println(s"Creating new $account with id = $newId")
accounts.update(newId, account.copy(id = newId))
} else {
Thread.sleep(300)
println(s"Updating existing $account")
accounts.update(account.id, account)
}
account
}
}
case object AccountService {
val repo = AccountRepository
val notifier = NotificationService
def debit(amount: Double, accountId: Int) = ???
def credit(amount: Double, accountId: Int) = ???
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment