2

I have some golang gin application. Under the hood it launch several goroutines, that execute some sql queries. But some queries are identical. So I decide to use local data cache (within single gin request) I tried using gin context but it doesn't work

type BaseRepository struct {
    BaseRepositoryInterface
    Db      *gorm.DB
    Context *gin.Context
}

type CoreWebsiteRepository struct {
    *BaseRepository
}

func (repository *CoreWebsiteRepository) GetResourceCenterCityId(websiteId int) (int, error) {
    if websiteId == 0 {
        return 0, fmt.Errorf("website_id is empty")
    }

    cacheKeyId := fmt.Sprintf("resource_center_city_id_by_website_id_%d", websiteId)
    value, exists := repository.Context.Get(cacheKeyId)
    if exists {
        return value.(int), nil
    }

    var data model.CoreWebsite
    err := repository.Db.Model(&model.CoreWebsite{}).
        Where("website_id = ?", websiteId).
        First(&data).
        Error
    if err != nil {
        return 0, err
    }

    repository.Context.Set(cacheKeyId, data.ResourceCenterCityId)

    return data.ResourceCenterCityId, nil
}

But caching doesn't work. I see several lines in the logs (per one gin request):

SELECT * FROM `core_website` WHERE website_id = 1510 ORDER BY `core_website`.`website_id` LIMIT 1

How to properly cache data so that goroutines can exchange them with each other?

Smirnov
  • 137
  • 3
  • 12
  • Do you use singletons `BaseRepository`, or confirm the `Context` is singletons. – Trock Aug 29 '23 at 03:04
  • yes I this it is singleton
    
    func NewCoreWebsiteRepository(context *gin.Context) CoreWebsiteRepositoryInterface {
        repo := tnRepository.NewBaseRepository(database.GetGormDbInstance(), context).(*tnRepository.BaseRepository)
        return &CoreWebsiteRepository{repo}
    }
    
    Context passed as parameter from handler
    – Smirnov Aug 29 '23 at 07:48
  • So how do you call `NewCoreWebsiteRepository`. This will work well If it's `NewCoreWebsiteRepository(&gin.Context{})`. – Trock Aug 29 '23 at 08:24
  • ```coreWebsiteRepository := tnRepository.NewCoreWebsiteRepository(method.Context) resourceCenterCityId, _ = coreWebsiteRepository.GetResourceCenterCityId(method.Request.Quote.WebsiteId) ``` where method.Context come from gin – Smirnov Aug 30 '23 at 05:46
  • @trock, is it right way to use gin.Context for local caching? can it actually work like that? – Smirnov Aug 30 '23 at 07:28
  • 1
    You can see [gin.Context](https://github.com/gin-gonic/gin/blob/dc9cff732e27ce4ac21b25772a83c462a28b8b80/context.go#L51). it's [Set](https://github.com/gin-gonic/gin/blob/dc9cff732e27ce4ac21b25772a83c462a28b8b80/context.go#L249).eg implement by `map[string]any` and `sync.RWMutex`. So if you just use these method, it will be ok. Or you can use like `sync.Map`. Your `method.Context` mean every http request will use an new `context`, so change it to singletons (global variable.eg). – Trock Aug 31 '23 at 10:29

0 Answers0