Lock With Redis
TIL
635
Scala
50
Redis
10
White

Vu Nhat Minh viết ngày 24/08/2016

Lock With Redis

Đặt gạch, sẽ viết cụ thể hơn về Lock bằng Redis (setnx) :smile:
http://redis.io/commands/setnx

abstract class RedisLock
extends UsesExecutionContext
{
  val lockTimeout = 30000L // 30s
  val now = new DateTime()
  private[this] val client = new ReadableWritableRedisClient

  /**
    * Redis Lock Algorithm:http://redis.io/commands/setnx
    */
  def withLockInRedis[R](key: String)(f: => Future[R]): Future[R] = {
    {
      for {
        lockHoldingTime <- lock(key)
        expired <- {
          lockHoldingTime match {
            case Some(_: Long) => Future(false)
            case None => isExpired(key)
          }
        }
        _ <- {
          if (lockHoldingTime.isEmpty && !expired) {
            Future.failed(new LockedException)
          } else if (lockHoldingTime.isEmpty && expired) {
            tryToAcquireAfterExpire(key).map {
              case false => throw new FailedToAcquireLockException
              case true => ()
            }
          } else {
            Future(())
          }
        }
        result <- f
        _ <- {
          lockHoldingTime match {
            case Some(t: Long) => releaseLock(key, t).map {
              case false => throw new FailedToReleaseLockException
              case true => ()
            }
            case None => Future(())
          }
        }
      } yield {
        result
      }
    }
  }

  def lock(key: String): Future[Option[Long]] = {
    val expireTime = now.getMillis + lockTimeout + 1
    client.setNx(key, expireTime.toString)
    .map{Option(_).collect{case true => expireTime}}
  }

  def isExpired(key: String): Future[Boolean] = {
    client.getString(key).map { v =>
      val setTime = v.getOrElse(throw new RedisException(s"can not get with key: $key")).toLong
      setTime < now.getMillis
    }.recover {
      case e:RedisException => false
    }
  }

  def tryToAcquireAfterExpire(key: String): Future[Boolean] = {
    val expireTime = now.getMillis + lockTimeout + 1
    client.getSet(key, expireTime.toString)
    .map { v =>
      val oldTimeStamp = v.getOrElse(throw new RedisException(s"cant not getset with key: $key")).toLong
      oldTimeStamp < now.getMillis
    }.recover {
      case e:RedisException => false
    }
  }

  def releaseLock(key: String, setValue: Long): Future[Boolean] = {
    client.getString(key).map { v =>
      val lockValue = v.getOrElse(throw new RedisException(s"cant not get with key: $key")).toLong
      val recognizedMyLock = lockValue == setValue
      if (recognizedMyLock) client.delete(key)
      recognizedMyLock
    }.recover {
      case e: RedisException => false
    }
  }
}

VuNhatMinh 23-08-2016

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Vu Nhat Minh

54 bài viết.
820 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
128 30
Nếu bạn thường vào trang mua sắm của amazon, chắc sẽ chẳng lạ gì với menu Shop by Department. Tốc độ hiển thị nội dung của menu là tức thì so với d...
Vu Nhat Minh viết 3 năm trước
128 30
White
100 4
Lời người dịch Người dịch là một developer , sau khi tìm đọc được bài viết này bằng bản gốc tiếng Anh đã cảm thấy như được "khai sáng" về khả năng...
Vu Nhat Minh viết hơn 3 năm trước
100 4
White
68 7
Form là thành phần quan trọng nhất khi design flow đăng ký của 1 web hay 1 app, dù là view gồm nhiều bước hay chỉ là một màn hình đơn điệu. Bài này...
Vu Nhat Minh viết gần 2 năm trước
68 7
Bài viết liên quan
White
3 0
Mở đầu Chắc hẳn các bạn đã biết về các dịch vụ rút gọn url, điển hình là bit.ly. Mục đích của dịch vụ này là nhằm thu gọn là những url rất dài để ...
huydx viết hơn 3 năm trước
3 0
White
23 5
1. Giới thiệu Redis]] là hệ thống lưu trữ keyvalue với rất nhiều tính năng và được sử dụng rộng rãi]]. Redis nổi bật bởi việc hỗ trợ nhiều cấu trú...
Bùi Hồng Hà viết hơn 3 năm trước
23 5
White
2 2
Chuẩn bị Update thư viện: sudo aptget update Cài trình biên dịch (nếu chưa có) sudo aptget install buildessential Cài tcl
Vũ Hoàng Chung viết 3 năm trước
2 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
54 bài viết.
820 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!