Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
17210d18
Commit
17210d18
authored
Jun 17, 2014
by
Don Mitchell
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4078 from edx/dhm/heartbeat
Refactor heartbeat to delegate to the modulestores and sql
parents
0b37c987
3c9b1011
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
142 additions
and
11 deletions
+142
-11
common/djangoapps/contentserver/tests/test.py
+0
-1
common/djangoapps/heartbeat/tests/__init__.py
+0
-0
common/djangoapps/heartbeat/tests/test_heartbeat.py
+45
-0
common/djangoapps/heartbeat/views.py
+25
-10
common/lib/xmodule/xmodule/exceptions.py
+17
-0
common/lib/xmodule/xmodule/modulestore/__init__.py
+6
-0
common/lib/xmodule/xmodule/modulestore/mixed.py
+13
-0
common/lib/xmodule/xmodule/modulestore/mongo/base.py
+10
-0
common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py
+10
-0
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+6
-0
common/lib/xmodule/xmodule/modulestore/xml.py
+10
-0
No files found.
common/djangoapps/contentserver/tests/test.py
View file @
17210d18
...
@@ -15,7 +15,6 @@ from django.test.utils import override_settings
...
@@ -15,7 +15,6 @@ from django.test.utils import override_settings
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
from
xmodule.contentstore.django
import
contentstore
,
_CONTENTSTORE
from
xmodule.contentstore.django
import
contentstore
,
_CONTENTSTORE
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
xmodule.modulestore.tests.django_utils
import
(
studio_store_config
,
from
xmodule.modulestore.tests.django_utils
import
(
studio_store_config
,
...
...
common/djangoapps/heartbeat/tests/__init__.py
0 → 100644
View file @
17210d18
common/djangoapps/heartbeat/tests/test_heartbeat.py
0 → 100644
View file @
17210d18
"""
Test the heartbeat
"""
from
django.test.client
import
Client
from
django.core.urlresolvers
import
reverse
import
json
from
django.db.utils
import
DatabaseError
import
mock
from
django.test.utils
import
override_settings
from
django.conf
import
settings
from
django.test.testcases
import
TestCase
from
xmodule.modulestore.tests.django_utils
import
mongo_store_config
TEST_MODULESTORE
=
mongo_store_config
(
settings
.
TEST_ROOT
/
"data"
)
@override_settings
(
MODULESTORE
=
TEST_MODULESTORE
)
class
HeartbeatTestCase
(
TestCase
):
"""
Test the heartbeat
"""
def
setUp
(
self
):
self
.
client
=
Client
()
self
.
heartbeat_url
=
reverse
(
'heartbeat'
)
return
super
(
HeartbeatTestCase
,
self
)
.
setUp
()
def
tearDown
(
self
):
return
super
(
HeartbeatTestCase
,
self
)
.
tearDown
()
def
test_success
(
self
):
response
=
self
.
client
.
get
(
self
.
heartbeat_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
def
test_sql_fail
(
self
):
with
mock
.
patch
(
'heartbeat.views.connection'
)
as
mock_connection
:
mock_connection
.
cursor
.
return_value
.
execute
.
side_effect
=
DatabaseError
response
=
self
.
client
.
get
(
self
.
heartbeat_url
)
self
.
assertEqual
(
response
.
status_code
,
503
)
response_dict
=
json
.
loads
(
response
.
content
)
self
.
assertIn
(
'SQL'
,
response_dict
)
def
test_mongo_fail
(
self
):
with
mock
.
patch
(
'pymongo.MongoClient.alive'
,
return_value
=
False
):
response
=
self
.
client
.
get
(
self
.
heartbeat_url
)
self
.
assertEqual
(
response
.
status_code
,
503
)
common/djangoapps/heartbeat/views.py
View file @
17210d18
import
json
from
datetime
import
datetime
from
pytz
import
UTC
from
django.http
import
HttpResponse
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
dogapi
import
dog_stats_api
from
dogapi
import
dog_stats_api
from
util.json_request
import
JsonResponse
from
django.db
import
connection
from
django.db.utils
import
DatabaseError
from
xmodule.exceptions
import
HeartbeatFailure
@dog_stats_api.timed
(
'edxapp.heartbeat'
)
@dog_stats_api.timed
(
'edxapp.heartbeat'
)
def
heartbeat
(
request
):
def
heartbeat
(
request
):
"""
"""
Simple view that a loadbalancer can check to verify that the app is up
Simple view that a loadbalancer can check to verify that the app is up. Returns a json doc
of service id: status or message. If the status for any service is anything other than True,
it returns HTTP code 503 (Service Unavailable); otherwise, it returns 200.
"""
"""
output
=
{
# This refactoring merely delegates to the default modulestore (which if it's mixed modulestore will
'date'
:
datetime
.
now
(
UTC
)
.
isoformat
(),
# delegate to all configured modulestores) and a quick test of sql. A later refactoring may allow
'courses'
:
[
course
.
location
.
to_deprecated_string
()
for
course
in
modulestore
()
.
get_courses
()],
# any service to register itself as participating in the heartbeat. It's important that all implementation
}
# do as little as possible but give a sound determination that they are ready.
return
HttpResponse
(
json
.
dumps
(
output
,
indent
=
4
))
try
:
output
=
modulestore
()
.
heartbeat
()
except
HeartbeatFailure
as
fail
:
return
JsonResponse
({
fail
.
service
:
unicode
(
fail
)},
status
=
503
)
cursor
=
connection
.
cursor
()
try
:
cursor
.
execute
(
"SELECT CURRENT_DATE"
)
cursor
.
fetchone
()
output
[
'SQL'
]
=
True
except
DatabaseError
as
fail
:
return
JsonResponse
({
'SQL'
:
unicode
(
fail
)},
status
=
503
)
return
JsonResponse
(
output
)
common/lib/xmodule/xmodule/exceptions.py
View file @
17210d18
...
@@ -38,3 +38,20 @@ class UndefinedContext(Exception):
...
@@ -38,3 +38,20 @@ class UndefinedContext(Exception):
Tried to access an xmodule field which needs a different context (runtime) to have a value.
Tried to access an xmodule field which needs a different context (runtime) to have a value.
"""
"""
pass
pass
class
HeartbeatFailure
(
Exception
):
"""
Raised when heartbeat fails.
"""
def
__unicode__
(
self
,
*
args
,
**
kwargs
):
return
self
.
message
def
__init__
(
self
,
msg
,
service
):
"""
In addition to a msg, provide the name of the service.
"""
self
.
service
=
service
return
super
(
HeartbeatFailure
,
self
)
.
__init__
(
msg
)
common/lib/xmodule/xmodule/modulestore/__init__.py
View file @
17210d18
...
@@ -362,6 +362,12 @@ class ModuleStoreReadBase(ModuleStoreRead):
...
@@ -362,6 +362,12 @@ class ModuleStoreReadBase(ModuleStoreRead):
else
:
else
:
return
any
(
c
.
id
==
course_id
for
c
in
self
.
get_courses
())
return
any
(
c
.
id
==
course_id
for
c
in
self
.
get_courses
())
def
heartbeat
(
self
):
"""
Is this modulestore ready?
"""
# default is to say yes by not raising an exception
return
{
'default_impl'
:
True
}
class
ModuleStoreWriteBase
(
ModuleStoreReadBase
,
ModuleStoreWrite
):
class
ModuleStoreWriteBase
(
ModuleStoreReadBase
,
ModuleStoreWrite
):
'''
'''
...
...
common/lib/xmodule/xmodule/modulestore/mixed.py
View file @
17210d18
...
@@ -19,6 +19,7 @@ from opaque_keys.edx.keys import CourseKey, UsageKey
...
@@ -19,6 +19,7 @@ from opaque_keys.edx.keys import CourseKey, UsageKey
from
xmodule.modulestore.mongo.base
import
MongoModuleStore
from
xmodule.modulestore.mongo.base
import
MongoModuleStore
from
xmodule.modulestore.split_mongo.split
import
SplitMongoModuleStore
from
xmodule.modulestore.split_mongo.split
import
SplitMongoModuleStore
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
import
itertools
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -332,6 +333,18 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -332,6 +333,18 @@ class MixedModuleStore(ModuleStoreWriteBase):
courses
.
extend
(
modulestore
.
get_courses_for_wiki
(
wiki_slug
))
courses
.
extend
(
modulestore
.
get_courses_for_wiki
(
wiki_slug
))
return
courses
return
courses
def
heartbeat
(
self
):
"""
Delegate to each modulestore and package the results for the caller.
"""
# could be done in parallel threads if needed
return
dict
(
itertools
.
chain
.
from_iterable
(
store
.
heartbeat
()
.
iteritems
()
for
store
in
self
.
modulestores
.
itervalues
()
)
)
def
_compare_stores
(
left
,
right
):
def
_compare_stores
(
left
,
right
):
"""
"""
...
...
common/lib/xmodule/xmodule/modulestore/mongo/base.py
View file @
17210d18
...
@@ -38,6 +38,7 @@ from xmodule.modulestore.inheritance import own_metadata, InheritanceMixin, inhe
...
@@ -38,6 +38,7 @@ from xmodule.modulestore.inheritance import own_metadata, InheritanceMixin, inhe
from
xmodule.tabs
import
StaticTab
,
CourseTabList
from
xmodule.tabs
import
StaticTab
,
CourseTabList
from
xblock.core
import
XBlock
from
xblock.core
import
XBlock
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
xmodule.exceptions
import
HeartbeatFailure
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -1034,3 +1035,12 @@ class MongoModuleStore(ModuleStoreWriteBase):
...
@@ -1034,3 +1035,12 @@ class MongoModuleStore(ModuleStoreWriteBase):
field_data
=
KvsFieldData
(
kvs
)
field_data
=
KvsFieldData
(
kvs
)
return
field_data
return
field_data
def
heartbeat
(
self
):
"""
Check that the db is reachable.
"""
if
self
.
database
.
connection
.
alive
():
return
{
MONGO_MODULESTORE_TYPE
:
True
}
else
:
raise
HeartbeatFailure
(
"Can't connect to {}"
.
format
(
self
.
database
.
name
),
'mongo'
)
common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py
View file @
17210d18
...
@@ -4,6 +4,7 @@ Segregation of pymongo functions from the data modeling mechanisms for split mod
...
@@ -4,6 +4,7 @@ Segregation of pymongo functions from the data modeling mechanisms for split mod
import
re
import
re
import
pymongo
import
pymongo
from
bson
import
son
from
bson
import
son
from
xmodule.exceptions
import
HeartbeatFailure
class
MongoConnection
(
object
):
class
MongoConnection
(
object
):
"""
"""
...
@@ -41,6 +42,15 @@ class MongoConnection(object):
...
@@ -41,6 +42,15 @@ class MongoConnection(object):
self
.
structures
.
write_concern
=
{
'w'
:
1
}
self
.
structures
.
write_concern
=
{
'w'
:
1
}
self
.
definitions
.
write_concern
=
{
'w'
:
1
}
self
.
definitions
.
write_concern
=
{
'w'
:
1
}
def
heartbeat
(
self
):
"""
Check that the db is reachable.
"""
if
self
.
database
.
connection
.
alive
():
return
True
else
:
raise
HeartbeatFailure
(
"Can't connect to {}"
.
format
(
self
.
database
.
name
))
def
get_structure
(
self
,
key
):
def
get_structure
(
self
,
key
):
"""
"""
Get the structure from the persistence mechanism whose id is the given key
Get the structure from the persistence mechanism whose id is the given key
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
17210d18
...
@@ -1769,3 +1769,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1769,3 +1769,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
"""
courses
=
[]
courses
=
[]
return
courses
return
courses
def
heartbeat
(
self
):
"""
Check that the db is reachable.
"""
return
{
SPLIT_MONGO_MODULESTORE_TYPE
:
self
.
db_connection
.
heartbeat
()}
common/lib/xmodule/xmodule/modulestore/xml.py
View file @
17210d18
...
@@ -815,3 +815,13 @@ class XMLModuleStore(ModuleStoreReadBase):
...
@@ -815,3 +815,13 @@ class XMLModuleStore(ModuleStoreReadBase):
"""
"""
courses
=
self
.
get_courses
()
courses
=
self
.
get_courses
()
return
[
course
.
location
for
course
in
courses
if
(
course
.
wiki_slug
==
wiki_slug
)]
return
[
course
.
location
for
course
in
courses
if
(
course
.
wiki_slug
==
wiki_slug
)]
def
heartbeat
(
self
):
"""
Ensure that every known course is loaded and ready to go. Really, just return b/c
if this gets called the __init__ finished which means the courses are loaded.
Returns the course count
"""
return
{
XML_MODULESTORE_TYPE
:
True
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment