Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add cache in exam, term info #176

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/common/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func init() {
config.Init(serviceName)
logger.Init(serviceName, config.GetLoggerLevel())
// eshook.InitLoggerWithHook(serviceName)
clientSet = base.NewClientSet(base.WithDBClient(constants.NoticeTableName))
clientSet = base.NewClientSet(base.WithDBClient(constants.NoticeTableName), base.WithRedisClient(constants.RedisDBCommon))
noticeSyncer = syncer.InitNoticeSyncer(clientSet.DBClient)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/classroom/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (s *ClassroomServiceImpl) GetExamRoomInfo(ctx context.Context, req *classro
resp = classroom.NewExamRoomInfoResponse()
rooms, err := service.NewClassroomService(ctx, s.ClientSet).GetExamRoomInfo(req)
if err != nil {
logger.Infof("Classroom.GetExamRoomInfo: Get exam room info fail %v", err)
base.LogError(fmt.Errorf("Classroom.GetExamRoomInfo: get exam info failed, err: %w", err))
resp.Base = base.BuildBaseResp(err)
return resp, nil
}
Expand Down
15 changes: 13 additions & 2 deletions internal/classroom/service/get_exam_room.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,25 @@ import (

func (s *ClassroomService) GetExamRoomInfo(req *classroom.ExamRoomInfoRequest) ([]*jwch.ExamRoomInfo, error) {
// login data 从 ctx 中获取

loginData, err := context.GetLoginData(s.ctx)
if err != nil {
return nil, fmt.Errorf("service.GetExamRoomInfo: Get login data fail %w", err)
}
key := fmt.Sprintf("exam:user:%s:term:%s", loginData.GetId(), req.GetTerm())

if s.cache.IsKeyExist(s.ctx, key) {
examRooms, err := s.cache.Classroom.GetExamRoom(s.ctx, key)
if err != nil {
return nil, fmt.Errorf("service.GetExamRoomInfo: Get exam room fail %w", err)
}
return examRooms, nil
}
stu := jwch.NewStudent().WithLoginData(loginData.Id, utils.ParseCookies(loginData.Cookies))
rooms, err := stu.GetExamRoom(jwch.ExamRoomReq{Term: req.Term})
examRooms, err := stu.GetExamRoom(jwch.ExamRoomReq{Term: req.Term})
if err = base.HandleJwchError(err); err != nil {
return nil, fmt.Errorf("service.GetExamRoomInfo: Get exam room info fail %w", err)
}
return rooms, nil
go s.cache.Classroom.SetExamRoom(s.ctx, key, examRooms)
return examRooms, nil
}
23 changes: 21 additions & 2 deletions internal/classroom/service/get_exam_room_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
"github.com/west2-online/fzuhelper-server/kitex_gen/model"
"github.com/west2-online/fzuhelper-server/pkg/base"
customContext "github.com/west2-online/fzuhelper-server/pkg/base/context"
"github.com/west2-online/fzuhelper-server/pkg/cache"
classroomCache "github.com/west2-online/fzuhelper-server/pkg/cache/classroom"
"github.com/west2-online/jwch"
)

Expand All @@ -36,18 +38,29 @@ func TestGetExamRoomInfo(t *testing.T) {
mockReturn interface{}
expectedResult interface{}
expectingError bool
expectedCached bool
}

tests := []testCase{
{
name: "GetExamRoomInfo",
name: "GetExamRoomInfoWithoutCache",
mockReturn: []*jwch.ExamRoomInfo{
{Location: "旗山东1"},
},
expectedResult: []*jwch.ExamRoomInfo{
{Location: "旗山东1"},
},
expectingError: true,
expectingError: false,
},
{
name: "GetExamRoomInfoFromCache",
mockReturn: []*jwch.ExamRoomInfo{
{Location: "旗山东1"},
},
expectedResult: []*jwch.ExamRoomInfo{
{Location: "旗山东1"},
},
expectingError: false,
},
}

Expand All @@ -61,8 +74,14 @@ func TestGetExamRoomInfo(t *testing.T) {
for _, tc := range tests {
mockey.PatchConvey(tc.name, t, func() {
mockClientSet := new(base.ClientSet)
mockClientSet.CacheClient = new(cache.Cache)
mockey.Mock((*cache.Cache).IsKeyExist).To(func(ctx context.Context, key string) bool {
return tc.expectedCached
}).Build()
mockey.Mock((*classroomCache.CacheClassroom).GetExamRoom).Return(tc.mockReturn, nil).Build()
mockey.Mock((*jwch.Student).WithLoginData).Return(jwch.NewStudent()).Build()
mockey.Mock((*jwch.Student).GetExamRoom).Return(tc.mockReturn, nil).Build()
mockey.Mock((*classroomCache.CacheClassroom).SetExamRoom).To(func(ctx context.Context, key string, value []*jwch.ExamRoomInfo) {}).Build()
// mock login data
loginData := new(model.LoginData)
ctx := customContext.WithLoginData(context.Background(), loginData)
Expand Down
6 changes: 5 additions & 1 deletion internal/common/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,12 @@ func (s *CommonServiceImpl) GetTermsList(ctx context.Context, req *common.TermLi
func (s *CommonServiceImpl) GetTerm(ctx context.Context, req *common.TermRequest) (resp *common.TermResponse, err error) {
resp = common.NewTermResponse()

res, err := service.NewCommonService(ctx, s.ClientSet).GetTerm(req)
success, res, err := service.NewCommonService(ctx, s.ClientSet).GetTerm(req)
if err != nil {
base.LogError(fmt.Errorf("Common.GetTerm: get term info failed: %w", err))
}

if !success {
resp.Base = base.BuildBaseResp(fmt.Errorf("Common.GetTerm: get term failed: %w", err))
return resp, nil
}
Expand Down
11 changes: 7 additions & 4 deletions internal/common/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"

"github.com/west2-online/fzuhelper-server/pkg/base"
"github.com/west2-online/fzuhelper-server/pkg/cache"
"github.com/west2-online/fzuhelper-server/pkg/db"
)

Expand All @@ -30,13 +31,15 @@ const (
)

type CommonService struct {
ctx context.Context
db *db.Database
ctx context.Context
db *db.Database
cache *cache.Cache
}

func NewCommonService(ctx context.Context, clientset *base.ClientSet) *CommonService {
return &CommonService{
ctx: ctx,
db: clientset.DBClient,
ctx: ctx,
db: clientset.DBClient,
cache: clientset.CacheClient,
}
}
22 changes: 18 additions & 4 deletions internal/common/service/term.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,24 @@ func (s *CommonService) GetTermList() (*jwch.SchoolCalendar, error) {
return calendar, nil
}

func (s *CommonService) GetTerm(req *common.TermRequest) (*jwch.CalTermEvents, error) {
events, err := jwch.NewStudent().GetTermEvents(req.Term)
func (s *CommonService) GetTerm(req *common.TermRequest) (bool, *jwch.CalTermEvents, error) {
var err error
var events *jwch.CalTermEvents

key := s.cache.Common.TermInfoKey(req.Term)
if s.cache.IsKeyExist(s.ctx, key) {
events, err = s.cache.Common.GetTermInfo(s.ctx, key)
if err != nil {
return false, nil, fmt.Errorf("service.GetTerm: Get term failed %w", err)
}
return true, events, nil
}
events, err = jwch.NewStudent().GetTermEvents(req.Term)
if err = base.HandleJwchError(err); err != nil {
return nil, fmt.Errorf("service.GetTerm: Get term failed %w", err)
return false, nil, fmt.Errorf("service.GetTerm: Get term failed %w", err)
}
if err = s.cache.Common.SetTermInfo(s.ctx, key, events); err != nil {
return true, nil, fmt.Errorf("service.GetTerm set term info cache failed %w", err)
}
return events, nil
return true, events, err
}
56 changes: 52 additions & 4 deletions internal/common/service/term_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (

"github.com/west2-online/fzuhelper-server/kitex_gen/common"
"github.com/west2-online/fzuhelper-server/pkg/base"
"github.com/west2-online/fzuhelper-server/pkg/cache"
cacheCommon "github.com/west2-online/fzuhelper-server/pkg/cache/common"
"github.com/west2-online/jwch"
)

Expand Down Expand Up @@ -97,6 +99,8 @@ func TestGetTerm(t *testing.T) {
expectedError bool
expectedErrorInfo error
expectedResult *jwch.CalTermEvents
expectedGetInfo bool
expectedCached bool
}

expectedResult := &jwch.CalTermEvents{
Expand Down Expand Up @@ -144,35 +148,79 @@ func TestGetTerm(t *testing.T) {

testCases := []TestCase{
{
Name: "GetTermSuccessfully",
Name: "GetTermSuccessfullyWithoutCache",
expectedError: false,
expectedErrorInfo: nil,
expectedResult: expectedResult,
expectedGetInfo: true,
expectedCached: false,
},
{
Name: "GetTermError",
expectedError: true,
expectedErrorInfo: errors.New("get term events failed"),
expectedResult: nil,
expectedGetInfo: false,
expectedCached: false,
},
{
Name: "GetTermFromCache",
expectedError: false,
expectedErrorInfo: nil,
expectedResult: expectedResult,
expectedGetInfo: true,
expectedCached: true,
},
{
Name: "CachedButGetTermError",
expectedError: true,
expectedErrorInfo: errors.New("Get term events failed"),
expectedResult: nil,
expectedGetInfo: false,
expectedCached: true,
},
{
Name: "SetCacheError",
expectedError: true,
expectedErrorInfo: errors.New("Set term events failed in cache"),
expectedResult: nil,
expectedGetInfo: false,
expectedCached: false,
},
}

defer mockey.UnPatchAll()
req := &common.TermRequest{Term: "201501"}
for _, tc := range testCases {
mockey.PatchConvey(tc.Name, t, func() {
ClientSet := new(base.ClientSet)
ClientSet.CacheClient = new(cache.Cache)
commonService := NewCommonService(context.Background(), ClientSet)
mockey.Mock((*cache.Cache).IsKeyExist).To(func(ctx context.Context, key string) bool {
return tc.expectedCached
}).Build()
mockey.Mock((*cacheCommon.CacheCommon).TermInfoKey).To(func(term string) string {
return "key"
}).Build()
mockey.Mock((*cacheCommon.CacheCommon).GetTermInfo).To(func(ctx context.Context, key string) (*jwch.CalTermEvents, error) {
return tc.expectedResult, tc.expectedErrorInfo
}).Build()
mockey.Mock((*jwch.Student).GetTermEvents).To(func(termId string) (*jwch.CalTermEvents, error) {
return tc.expectedResult, tc.expectedErrorInfo
}).Build()
ClientSet := new(base.ClientSet)
commonService := NewCommonService(context.Background(), ClientSet)
result, err := commonService.GetTerm(req)
mockey.Mock((*cacheCommon.CacheCommon).SetTermInfo).To(func(ctx context.Context, key string, value *jwch.CalTermEvents) error {
return tc.expectedErrorInfo
}).Build()

success, result, err := commonService.GetTerm(req)
if tc.expectedError {
assert.EqualError(t, err, "service.GetTerm: Get term failed "+tc.expectedErrorInfo.Error())
assert.Nil(t, result)
assert.Equal(t, tc.expectedGetInfo, success)
} else {
assert.Nil(t, err, tc.expectedErrorInfo)
assert.Equal(t, tc.expectedResult, result)
assert.Equal(t, tc.expectedGetInfo, success)
}
})
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/redis/go-redis/v9"

"github.com/west2-online/fzuhelper-server/pkg/cache/classroom"
"github.com/west2-online/fzuhelper-server/pkg/cache/common"
"github.com/west2-online/fzuhelper-server/pkg/cache/launch_screen"
"github.com/west2-online/fzuhelper-server/pkg/cache/paper"
)
Expand All @@ -31,6 +32,7 @@ type Cache struct {
Classroom *classroom.CacheClassroom
Paper *paper.CachePaper
LaunchScreen *launch_screen.CacheLaunchScreen
Common *common.CacheCommon
}

func NewCache(client *redis.Client) *Cache {
Expand All @@ -39,6 +41,7 @@ func NewCache(client *redis.Client) *Cache {
Classroom: classroom.NewCacheClassroom(client),
LaunchScreen: launch_screen.NewCacheLaunchScreen(client),
Paper: paper.NewCachePaper(client),
Common: common.NewCacheCommon(client),
}
}

Expand Down
39 changes: 39 additions & 0 deletions pkg/cache/classroom/get_exam_room.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Copyright 2024 The west2-online Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package classroom

import (
"context"

"github.com/bytedance/sonic"

"github.com/west2-online/fzuhelper-server/pkg/errno"
"github.com/west2-online/jwch"
)

func (c *CacheClassroom) GetExamRoom(ctx context.Context, key string) ([]*jwch.ExamRoomInfo, error) {
ret := make([]*jwch.ExamRoomInfo, 0)
data, err := c.client.Get(ctx, key).Result()
if err != nil {
return nil, errno.Errorf(errno.InternalDatabaseErrorCode, "dal.GetExamRoom: Get exam rooms info failed: %v", err)
}
err = sonic.Unmarshal([]byte(data), &ret)
if err != nil {
return nil, errno.Errorf(errno.InternalJSONErrorCode, "dal.GetExamRoom: Unmarshal exam rooms info failed: %v", err)
}
return ret, nil
}
42 changes: 42 additions & 0 deletions pkg/cache/classroom/set_exam_room.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Copyright 2024 The west2-online Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package classroom

import (
"context"
"time"

"github.com/bytedance/sonic"

"github.com/west2-online/fzuhelper-server/pkg/logger"
"github.com/west2-online/jwch"
)

const EXAMROOMEXPIRE = 5 * time.Minute

func (c *CacheClassroom) SetExamRoom(ctx context.Context, key string, value []*jwch.ExamRoomInfo) {
examRoomJson, err := sonic.Marshal(value)
if err != nil {
logger.Errorf("dal.SetExamRoom: marshal exam room info failed, err: %v", err)
return
}
err = c.client.Set(ctx, key, examRoomJson, EXAMROOMEXPIRE).Err()
if err != nil {
logger.Errorf("dal.SetExamRoom: set exam room failed, err: %v", err)
return
}
}
Loading
Loading