-
Notifications
You must be signed in to change notification settings - Fork 438
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
Adding a custom session handler with Cloud Datastore. #213
Conversation
85c7aec
to
ab60a5a
Compare
|
||
public function open($savePath, $sessionName) | ||
{ | ||
$this->datastore = new DatastoreClient( |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Added a constructor :) I will also add test. Maybe I can add unit test with mocking. Do you want to have a system test as well? |
Added the unit test. |
Maybe we should not ignore the How about to use |
I started to use However, utilizing |
Looking really nice @tmatsuo, thank you for this. While it is not documented , it is possible to pass a $key = $datastore->key('key', 1234, [
'namespaceId' => 'Namespace'
]); The idea of using the A few comments: Have you considered a form of locking at all? I'm a little concerned about the garbage collection. According to the docs |
sprintf('Datastore lookup failed: %s', $e->getMessage()), | ||
E_USER_NOTICE | ||
); | ||
return ''; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Good point. Maybe we can use the Datastore transaction? But it is a bit difficult with the current interface design. I think there are the same issues with any other session implementations.
Good point. Just for reducing the deletion cost (I think it's cheaper leaving entities than deleting them), maybe we can stop querying when gcLimit == 0 and document that. How does it sound? Also, when I deployed a sample app with this handler, App Engine health check is constantly creating a new session entities in the datastore. We should also recommend that users use this handler only for needed handlers. |
Also, is it same for query (which is needed in |
@dwsupplee I left it out of the documentation purposely because the right way to do it really is in the config. Most applications would want to use the same namespace across an entire project. If you think we should document it with a caveat I'm cool with that too. |
@jdpedrie Ah OK, great, I'll try to use that. BTW, another viable solution for the session in cloud is to use Google Cloud Storage with gcs stream wrapper. I will also try to implement the stream wrapper. Thanks, |
Actually, I believe the default session handler locks.
That sounds like a solid idea. I wonder if it would be best to default the limit to 0 so that a user has to explicitly ask for the query/deletion to occur. What do you think? |
I see. There's no exclusive lock in datastore. Maybe we can create a transaction on
Yeah I will do that. |
Now it uses the Does it sound reasonable? |
public function open($savePath, $sessionName) | ||
{ | ||
$this->kind = $sessionName; | ||
$this->namespaceId = str_replace('/', '_', $savePath); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
{ | ||
$this->kind = $sessionName; | ||
$this->namespaceId = str_replace('/', '_', $savePath); | ||
$this->transaction = $this->datastore->transaction(); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Hmm, I don't think we would just want the write to fail if we run into concurrency issues. I will do a little more research after having pulled down and played with the code a little bit. |
A session handler that requires more than register, call
Everything can fail, and obviously people should handle issues that can arise. That said, errors in the session handler are exceedingly rare. I can't recall ever running into one in the default implementation. I'd rather not accept an implementation which we know can fail in certain (not uncommon) circumstances. Documenting how to work around those errors doesn't strike me as a compromise that is in the best interests of our users. I think a Datastore session handler is a great idea, but as always the devil is in the details. As a user of the library, I would be worried about a session handler which was expected to fail in certain cases and which could very well cause problems for my users. |
@dwsupplee @jdpedrie But yeah, If you are not comfortable with this handler, I will just put it somewhere else :) |
In other words, all the peculiarity you feel from this handler, comes from the characteristic of the Datastore API itself. It provides the data consistency feature via it's transaction. It is optimistic lock which is not very well suited with the current PHP session's interface. The reason why this handler can not be a complete drop-in replacement for every use-case (like heavily complex data in session for complex ajax application) is, well, in the most part, it's due to the limit of the current PHP session interface and the default behavior. However, it's perfectly fine if you use this library just for sign-in and sign-out, even without setting the error handler, because awesome Also it's perfectly fine if you use this library with the error handler installed, if you have complex session data, and you don't want to lose them.
Hmm, I think you're lucky! Even filesystem based simple session handler can fail. In my opinion, if you don't want to lose any session data, only reliable way is to handle errors like I do in the sample, it applies to any other session implementations. |
I think this right here is what I'm looking for in the docs :). My only real concern at this point is someone thinking they can use it as a drop in replacement and being surprised by issues. If we make it clear what the best use cases are then I feel a lot better about putting it into people's hands. |
@dwsupplee |
It is my first attempt for the docblock update! PTAL @dwsupplee @jdpedrie |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The added documentation looks really helpful. Thanks for adding it!
@@ -26,6 +26,31 @@ | |||
* | |||
* {@see http://php.net/manual/en/class.sessionhandlerinterface.php} | |||
* | |||
* Instead of storing the session data in a local file, it stores the data to | |||
* Cloud Datastore. Biggest benefit of doing this is the data can be shared by |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* The downside of using Cloud Datastore is the write operations will cost you | ||
* some money, so it is highly recommended to minimize the write operations | ||
* with your session data with this handler. In order to do so, keep the data | ||
* in the session as few as possible; for example, it is ok to put only |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* operations will cause the Datastore write and then it will cost you lot of | ||
* money. | ||
* | ||
* This handler doesn't provide pesimistic lock for session data. Instead, it |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* | ||
* If you are building an ajax application which may issue multiple requests | ||
* to the server, please design the session data carefully, in order to avoid | ||
* possible data contentions. Also please see the 2nd exmaple in this docbock |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@jdpedrie Thanks for the review, all done. |
* | ||
* If you are building an ajax application which may issue multiple requests | ||
* to the server, please design the session data carefully, in order to avoid | ||
* possible data contentions. Also please see the 2nd exmaple in this docbock | ||
* for how to properly handle errors on `write` operations. | ||
* possible data contentions. Also please see the 2nd exmaple below for how to |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* | ||
* Example without error handling: | ||
* ``` | ||
* use Google\Cloud\Datastore\DatastoreClient; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* session_save_path('sessions'); | ||
* session_start(); | ||
* | ||
* # Then read and write the $_SESSION array. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
|
||
/** | ||
* @param DatastoreClient $datastore Datastore client. | ||
* @param int [optional] $gcLimit A number of entities to delete in the |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
} | ||
|
||
/** | ||
* @param string $savePath The value of `session.save_path` setting will be |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
return true; | ||
} | ||
|
||
public function close() |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
code looks good to me, but there are some docs issues still to be addressed. :) Thanks for working through these issues with us, @tmatsuo. |
You can test whether the parser fails by running this command:
|
@jdpedrie Alright, now it seems like it compiles, PTAL |
* | ||
* $cloud = new ServiceBuilder(); | ||
* $datastore = $cloud->datastore(); | ||
* // or just $datastore = new DatastoreClient(); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* used here. It will use this value as the Datastore kind. | ||
* @return bool | ||
*/ | ||
public function open($savePath, $sessionName) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
/** | ||
* Custom session handler backed by Cloud Datastore. | ||
* | ||
* {@see http://php.net/manual/en/class.sessionhandlerinterface.php} |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Looks good! Thanks @tmatsuo |
It's great if you give early feedback!