flarum / framework

Simple forum software for building great communities.
http://flarum.org/
6.29k stars 832 forks source link

PDOException : Duplicate entry '.....' for key 'posts_discussion_id_number_unique' #3350

Closed iPurpl3x closed 2 years ago

iPurpl3x commented 3 years ago

Bug Report

Current Behavior As suggested by @luceos this error happens "when two posts are saved at the same time".

Steps to Reproduce I never saw this error myself, I just found it in the logs of one of our production instances.

Expected Behavior No Error.

Error Logs

Next Doctrine\DBAL\Driver\PDO\Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1718-14' for key 'posts_discussion_id_number_unique' in /opt/flarum/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Exception.php:18
Stack trace:
#0 /opt/flarum/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php(117): Doctrine\DBAL\Driver\PDO\Exception::new(Object(PDOException))
flarum/framework#1 /opt/flarum/vendor/illuminate/database/Connection.php(458): Doctrine\DBAL\Driver\PDOStatement->execute()
flarum/framework#2 /opt/flarum/vendor/illuminate/database/Connection.php(657): Illuminate\Database\Connection->Illuminate\Database\{closure}('insert into `po...', Array)
flarum/framework#3 /opt/flarum/vendor/illuminate/database/Connection.php(624): Illuminate\Database\Connection->runQueryCallback('insert into `po...', Array, Object(Closure))
flarum/framework#4 /opt/flarum/vendor/illuminate/database/Connection.php(459): Illuminate\Database\Connection->run('insert into `po...', Array, Object(Closure))
flarum/framework#5 /opt/flarum/vendor/illuminate/database/Connection.php(411): Illuminate\Database\Connection->statement('insert into `po...', Array)
flarum/framework#6 /opt/flarum/vendor/illuminate/database/Query/Processors/Processor.php(32): Illuminate\Database\Connection->insert('insert into `po...', Array)
flarum/framework#7 /opt/flarum/vendor/illuminate/database/Query/Builder.php(2628): Illuminate\Database\Query\Processors\Processor->processInsertGetId(Object(Illuminate\Database\Query\Builder), 'insert into `po...', Array, 'id')
flarum/framework#8 /opt/flarum/vendor/illuminate/database/Eloquent/Builder.php(1338): Illuminate\Database\Query\Builder->insertGetId(Array, 'id')
flarum/framework#9 /opt/flarum/vendor/illuminate/database/Eloquent/Model.php(823): Illuminate\Database\Eloquent\Builder->__call('insertGetId', Array)
flarum/framework#10 /opt/flarum/vendor/illuminate/database/Eloquent/Model.php(788): Illuminate\Database\Eloquent\Model->insertAndSetId(Object(Illuminate\Database\Eloquent\Builder), Array)
flarum/framework#11 /opt/flarum/vendor/illuminate/database/Eloquent/Model.php(651): Illuminate\Database\Eloquent\Model->performInsert(Object(Illuminate\Database\Eloquent\Builder))
flarum/framework#12 /opt/flarum/vendor/flarum/core/src/Post/Command/PostReplyHandler.php(103): Illuminate\Database\Eloquent\Model->save()
flarum/framework#13 /opt/flarum/vendor/illuminate/bus/Dispatcher.php(90): Flarum\Post\Command\PostReplyHandler->handle(Object(Flarum\Post\Command\PostReply))
flarum/framework#14 /opt/flarum/vendor/illuminate/pipeline/Pipeline.php(128): Illuminate\Bus\Dispatcher->Illuminate\Bus\{closure}(Object(Flarum\Post\Command\PostReply))
flarum/framework#15 /opt/flarum/vendor/illuminate/pipeline/Pipeline.php(104): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Flarum\Post\Command\PostReply))
flarum/framework#16 /opt/flarum/vendor/illuminate/bus/Dispatcher.php(98): Illuminate\Pipeline\Pipeline->then(Object(Closure))
flarum/framework#17 /opt/flarum/vendor/illuminate/bus/Dispatcher.php(76): Illuminate\Bus\Dispatcher->dispatchNow(Object(Flarum\Post\Command\PostReply))
flarum/framework#18 /opt/flarum/vendor/flarum/core/src/Api/Controller/CreatePostController.php(73): Illuminate\Bus\Dispatcher->dispatch(Object(Flarum\Post\Command\PostReply))
flarum/framework#19 /opt/flarum/vendor/flarum/core/src/Api/Controller/AbstractSerializeController.php(96): Flarum\Api\Controller\CreatePostController->data(Object(Laminas\Diactoros\ServerRequest), Object(Tobscure\JsonApi\Document))
flarum/framework#20 /opt/flarum/vendor/flarum/core/src/Api/Controller/AbstractCreateController.php(22): Flarum\Api\Controller\AbstractSerializeController->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#21 /opt/flarum/vendor/flarum/core/src/Http/RouteHandlerFactory.php(38): Flarum\Api\Controller\AbstractCreateController->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#22 /opt/flarum/vendor/flarum/core/src/Http/Middleware/DispatchRoute.php(65): Flarum\Http\RouteHandlerFactory->Flarum\Http\{closure}(Object(Laminas\Diactoros\ServerRequest), Array)
flarum/framework#23 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\DispatchRoute->process(Object(Laminas\Diactoros\ServerRequest), Object(Closure))
flarum/framework#24 /opt/flarum/vendor/glowingblue/core/src/Middleware/ActorBindingMiddleware.php(34): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#25 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): GlowingBlue\Core\Middleware\ActorBindingMiddleware->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#26 /opt/flarum/vendor/glowingblue/core/src/Middleware/ServerRequestMiddleware.php(25): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#27 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): GlowingBlue\Core\Middleware\ServerRequestMiddleware->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#28 /opt/flarum/vendor/fof/sentry/src/Middleware/HandleErrorsWithSentry.php(28): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#29 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): FoF\Sentry\Middleware\HandleErrorsWithSentry->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#30 /opt/flarum/vendor/flarum/core/src/Http/Middleware/SetLocale.php(50): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#31 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\SetLocale->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#32 /opt/flarum/vendor/flarum/core/src/Http/Middleware/CheckCsrfToken.php(45): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#33 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\CheckCsrfToken->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#34 /opt/flarum/vendor/flarum/core/src/Http/Middleware/AuthenticateWithHeader.php(55): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#35 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\AuthenticateWithHeader->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#36 /opt/flarum/vendor/flarum/core/src/Http/Middleware/AuthenticateWithSession.php(32): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#37 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\AuthenticateWithSession->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#38 /opt/flarum/vendor/flarum/core/src/Http/Middleware/RememberFromCookie.php(51): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#39 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\RememberFromCookie->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#40 /opt/flarum/vendor/flarum/core/src/Http/Middleware/StartSession.php(61): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#41 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\StartSession->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#42 /opt/flarum/vendor/flarum/core/src/Api/Middleware/FakeHttpMethods.php(29): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#43 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Api\Middleware\FakeHttpMethods->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#44 /opt/flarum/vendor/flarum/core/src/Http/Middleware/ParseJsonBody.php(28): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#45 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\ParseJsonBody->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#46 /opt/flarum/vendor/flarum/core/src/Http/Middleware/HandleErrors.php(57): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#47 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\HandleErrors->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#48 /opt/flarum/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(84): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#49 /opt/flarum/vendor/middlewares/request-handler/src/RequestHandler.php(84): Laminas\Stratigility\MiddlewarePipe->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#50 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Middlewares\RequestHandler->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#51 /opt/flarum/vendor/middlewares/base-path-router/src/BasePathRouter.php(97): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#52 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Middlewares\BasePathRouter->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#53 /opt/flarum/vendor/laminas/laminas-stratigility/src/Middleware/OriginalMessages.php(42): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#54 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Laminas\Stratigility\Middleware\OriginalMessages->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#55 /opt/flarum/vendor/middlewares/base-path/src/BasePath.php(53): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#56 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Middlewares\BasePath->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#57 /opt/flarum/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(84): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#58 /opt/flarum/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(73): Laminas\Stratigility\MiddlewarePipe->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\EmptyPipelineHandler))
flarum/framework#59 /opt/flarum/vendor/laminas/laminas-httphandlerrunner/src/RequestHandlerRunner.php(96): Laminas\Stratigility\MiddlewarePipe->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#60 /opt/flarum/vendor/flarum/core/src/Http/Server.php(42): Laminas\HttpHandlerRunner\RequestHandlerRunner->run()
flarum/framework#61 /opt/flarum/public/index.php(26): Flarum\Http\Server->listen()
flarum/framework#62 {main}

Next Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1718-14' for key 'posts_discussion_id_number_unique' (SQL: insert into `posts` (`is_approved`, `created_at`, `discussion_id`, `user_id`, `type`, `ip_address`, `content`, `is_private`, `number`) values (1, 2021-01-18 19:22:16, 1718, 2253, comment, 5.144.28.90, <r><p><POSTMENTION discussionid="1718" displayname="MTR" id="12161" number="13" username="MTR">@MTR#12161</POSTMENTION> <br/>
Update: RT-AC86 ist angekommen und funktioniert perfekt! Keine probleme mehr</p></r>, 0, 14)) in /opt/flarum/vendor/illuminate/database/Connection.php:664
Stack trace:
#0 /opt/flarum/vendor/illuminate/database/Connection.php(624): Illuminate\Database\Connection->runQueryCallback('insert into `po...', Array, Object(Closure))
flarum/framework#1 /opt/flarum/vendor/illuminate/database/Connection.php(459): Illuminate\Database\Connection->run('insert into `po...', Array, Object(Closure))
flarum/framework#2 /opt/flarum/vendor/illuminate/database/Connection.php(411): Illuminate\Database\Connection->statement('insert into `po...', Array)
flarum/framework#3 /opt/flarum/vendor/illuminate/database/Query/Processors/Processor.php(32): Illuminate\Database\Connection->insert('insert into `po...', Array)
flarum/framework#4 /opt/flarum/vendor/illuminate/database/Query/Builder.php(2628): Illuminate\Database\Query\Processors\Processor->processInsertGetId(Object(Illuminate\Database\Query\Builder), 'insert into `po...', Array, 'id')
flarum/framework#5 /opt/flarum/vendor/illuminate/database/Eloquent/Builder.php(1338): Illuminate\Database\Query\Builder->insertGetId(Array, 'id')
flarum/framework#6 /opt/flarum/vendor/illuminate/database/Eloquent/Model.php(823): Illuminate\Database\Eloquent\Builder->__call('insertGetId', Array)
flarum/framework#7 /opt/flarum/vendor/illuminate/database/Eloquent/Model.php(788): Illuminate\Database\Eloquent\Model->insertAndSetId(Object(Illuminate\Database\Eloquent\Builder), Array)
flarum/framework#8 /opt/flarum/vendor/illuminate/database/Eloquent/Model.php(651): Illuminate\Database\Eloquent\Model->performInsert(Object(Illuminate\Database\Eloquent\Builder))
flarum/framework#9 /opt/flarum/vendor/flarum/core/src/Post/Command/PostReplyHandler.php(103): Illuminate\Database\Eloquent\Model->save()
flarum/framework#10 /opt/flarum/vendor/illuminate/bus/Dispatcher.php(90): Flarum\Post\Command\PostReplyHandler->handle(Object(Flarum\Post\Command\PostReply))
flarum/framework#11 /opt/flarum/vendor/illuminate/pipeline/Pipeline.php(128): Illuminate\Bus\Dispatcher->Illuminate\Bus\{closure}(Object(Flarum\Post\Command\PostReply))
flarum/framework#12 /opt/flarum/vendor/illuminate/pipeline/Pipeline.php(104): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Flarum\Post\Command\PostReply))
flarum/framework#13 /opt/flarum/vendor/illuminate/bus/Dispatcher.php(98): Illuminate\Pipeline\Pipeline->then(Object(Closure))
flarum/framework#14 /opt/flarum/vendor/illuminate/bus/Dispatcher.php(76): Illuminate\Bus\Dispatcher->dispatchNow(Object(Flarum\Post\Command\PostReply))
flarum/framework#15 /opt/flarum/vendor/flarum/core/src/Api/Controller/CreatePostController.php(73): Illuminate\Bus\Dispatcher->dispatch(Object(Flarum\Post\Command\PostReply))
flarum/framework#16 /opt/flarum/vendor/flarum/core/src/Api/Controller/AbstractSerializeController.php(96): Flarum\Api\Controller\CreatePostController->data(Object(Laminas\Diactoros\ServerRequest), Object(Tobscure\JsonApi\Document))
flarum/framework#17 /opt/flarum/vendor/flarum/core/src/Api/Controller/AbstractCreateController.php(22): Flarum\Api\Controller\AbstractSerializeController->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#18 /opt/flarum/vendor/flarum/core/src/Http/RouteHandlerFactory.php(38): Flarum\Api\Controller\AbstractCreateController->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#19 /opt/flarum/vendor/flarum/core/src/Http/Middleware/DispatchRoute.php(65): Flarum\Http\RouteHandlerFactory->Flarum\Http\{closure}(Object(Laminas\Diactoros\ServerRequest), Array)
flarum/framework#20 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\DispatchRoute->process(Object(Laminas\Diactoros\ServerRequest), Object(Closure))
flarum/framework#21 /opt/flarum/vendor/glowingblue/core/src/Middleware/ActorBindingMiddleware.php(34): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#22 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): GlowingBlue\Core\Middleware\ActorBindingMiddleware->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#23 /opt/flarum/vendor/glowingblue/core/src/Middleware/ServerRequestMiddleware.php(25): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#24 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): GlowingBlue\Core\Middleware\ServerRequestMiddleware->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#25 /opt/flarum/vendor/fof/sentry/src/Middleware/HandleErrorsWithSentry.php(28): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#26 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): FoF\Sentry\Middleware\HandleErrorsWithSentry->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#27 /opt/flarum/vendor/flarum/core/src/Http/Middleware/SetLocale.php(50): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#28 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\SetLocale->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#29 /opt/flarum/vendor/flarum/core/src/Http/Middleware/CheckCsrfToken.php(45): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#30 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\CheckCsrfToken->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#31 /opt/flarum/vendor/flarum/core/src/Http/Middleware/AuthenticateWithHeader.php(55): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#32 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\AuthenticateWithHeader->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#33 /opt/flarum/vendor/flarum/core/src/Http/Middleware/AuthenticateWithSession.php(32): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#34 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\AuthenticateWithSession->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#35 /opt/flarum/vendor/flarum/core/src/Http/Middleware/RememberFromCookie.php(51): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#36 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\RememberFromCookie->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#37 /opt/flarum/vendor/flarum/core/src/Http/Middleware/StartSession.php(61): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#38 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\StartSession->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#39 /opt/flarum/vendor/flarum/core/src/Api/Middleware/FakeHttpMethods.php(29): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#40 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Api\Middleware\FakeHttpMethods->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#41 /opt/flarum/vendor/flarum/core/src/Http/Middleware/ParseJsonBody.php(28): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#42 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\ParseJsonBody->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#43 /opt/flarum/vendor/flarum/core/src/Http/Middleware/HandleErrors.php(57): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#44 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Flarum\Http\Middleware\HandleErrors->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#45 /opt/flarum/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(84): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#46 /opt/flarum/vendor/middlewares/request-handler/src/RequestHandler.php(84): Laminas\Stratigility\MiddlewarePipe->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#47 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Middlewares\RequestHandler->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#48 /opt/flarum/vendor/middlewares/base-path-router/src/BasePathRouter.php(97): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#49 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Middlewares\BasePathRouter->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#50 /opt/flarum/vendor/laminas/laminas-stratigility/src/Middleware/OriginalMessages.php(42): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#51 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Laminas\Stratigility\Middleware\OriginalMessages->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#52 /opt/flarum/vendor/middlewares/base-path/src/BasePath.php(53): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#53 /opt/flarum/vendor/laminas/laminas-stratigility/src/Next.php(61): Middlewares\BasePath->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\Next))
flarum/framework#54 /opt/flarum/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(84): Laminas\Stratigility\Next->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#55 /opt/flarum/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(73): Laminas\Stratigility\MiddlewarePipe->process(Object(Laminas\Diactoros\ServerRequest), Object(Laminas\Stratigility\EmptyPipelineHandler))
flarum/framework#56 /opt/flarum/vendor/laminas/laminas-httphandlerrunner/src/RequestHandlerRunner.php(96): Laminas\Stratigility\MiddlewarePipe->handle(Object(Laminas\Diactoros\ServerRequest))
flarum/framework#57 /opt/flarum/vendor/flarum/core/src/Http/Server.php(42): Laminas\HttpHandlerRunner\RequestHandlerRunner->run()
flarum/framework#58 /opt/flarum/public/index.php(26): Flarum\Http\Server->listen()
flarum/framework#59 {main}

Environment

/opt/flarum # php flarum info
Flarum core 0.1.0-beta.13
PHP version: 7.4.15
Loaded extensions: Core, date, libxml, pcre, zlib, filter, hash, readline, Reflection, SPL, session, ctype, curl, dom, fileinfo, gd, gmp, json, mbstring, openssl, PDO, standard, tokenizer, xmlwriter, zip, exif, mysqlnd, Phar, pdo_mysql, Zend OPcache
+---------------------------------+------------------+------------------------------------------+
| Flarum Extensions               |                  |                                          |
+---------------------------------+------------------+------------------------------------------+
| ID                              | Version          | Commit                                   |
+---------------------------------+------------------+------------------------------------------+
| flarum-approval                 | v0.1.0-beta.13   |                                          |
| flarum-bbcode                   | v0.1.0-beta.12   |                                          |
| cbmainz-de                      | 0.12.1           |                                          |
| flarum-emoji                    | v0.1.0-beta.13   |                                          |
| flarum-flags                    | v0.1.0-beta.13   |                                          |
| flarum-lock                     | v0.1.0-beta.13   |                                          |
| flarum-mentions                 | v0.1.0-beta.13   |                                          |
| flarum-sticky                   | v0.1.0-beta.13   |                                          |
| flarum-subscriptions            | v0.1.0-beta.13   |                                          |
| flarum-suspend                  | v0.1.0-beta.13   |                                          |
| flarum-tags                     | v0.1.0-beta.13.2 |                                          |
| flarum-markdown                 | v0.1.0-beta.13   |                                          |
| flarum-akismet                  | v0.1.0-beta.13   |                                          |
| glowingblue-modmsg              | v0.1.2           | 73c6ff5a6e691548e53e8e0dfceca77d8d897b3b |
| fof-links                       | 0.3.0            |                                          |
| fof-pages                       | 0.4.0            |                                          |
| flarum-statistics               | v0.1.0-beta.13   |                                          |
| flarum-lang-english             | v0.1.0-beta.13   |                                          |
| datitisev-dashboard             | v0.1.0-beta.8.2  |                                          |
| kilowhat-mailing                | 0.2.4            |                                          |
| michaelbelgium-discussion-views | v4.0.1           |                                          |
| fof-default-user-preferences    | 0.2.0            |                                          |
| v17development-seo              | 1.3.1            |                                          |
| fof-masquerade                  | 0.3.4            |                                          |
| fof-byobu                       | 0.5.6            |                                          |
| fof-formatting                  | 0.1.5            |                                          |
| glowingblue-escalation          | v0.0.3           | 7464d87c69555827ae0fa879faf6a94d0f134778 |
| fof-linguist                    | 0.4.3            |                                          |
| fof-pretty-mail                 | 0.1.7            |                                          |
| fof-split                       | 0.4.4            |                                          |
| fof-user-directory              | 0.3.4            |                                          |
| glowingblue-handy-linguist      | v0.2.2           | 988bb09f789782c7062cb1729c870ebebebb4f0d |
| fof-follow-tags                 | 0.4.5            |                                          |
| fof-best-answer                 | 0.1.11           |                                          |
| fof-terms                       | 0.4.3            |                                          |
| glowingblue-scheduled-posts     | v0.1.5           | a688b5a4cfd9ddce43d4b2f1c48edb3aac490d5b |
| glowingblue-engage              | 0.1.11           | a8340486f7ab56ece39c1ef204d7841f0f0361b4 |
| fof-gamification                | 0.2.6            |                                          |
| glowingblue-composer-preview    | v0.1.5           | fd7e58c053883fe6ae1ef51c78363a597daae92b |
| franzl-open-links-in-new-tab    | v0.1.0           |                                          |
| fof-upload                      | 0.10.1           |                                          |
| flagrow-direct-links            | 0.2.0            |                                          |
| noriods-auto-more               | 0.3.0            |                                          |
| fof-merge-discussions           | 0.3.3            |                                          |
| fof-polls                       | 0.1.2-p2         | e88f4da0034c98296fc2ae73d75bf2e2717b2519 |
| fof-realtimedate                | 0.1.3            |                                          |
| the-turk-password-strength      | 1.0.2            |                                          |
| askvortsov-pwa                  | v1.0.7           |                                          |
| the-turk-extended-appearance    | 0.1.1            |                                          |
| askvortsov-moderator-warnings   | v0.2.4           |                                          |
| flarumite-decontaminator        | v0.1.6           | 5c027cf120fea7dff411f2171dfa270ccb9ab4a5 |
| fof-nightmode                   | 0.5.2            |                                          |
| fof-forum-statistics-widget     | 0.2.0            |                                          |
| fof-html-errors                 | 0.4.0            |                                          |
| fof-impersonate                 | 0.5.0            |                                          |
| fof-moderator-notes             | 0.2.4            |                                          |
| fof-sitemap                     | 0.5.3            |                                          |
| glowingblue-modern-theme        | v0.1.15          | ed055ae6766be9c4dc44fe0523db17bc8490adff |
| glowingblue-user-activity       | v0.1.1           | cbe7f0016115d6867583b96c853fdf2e63650eb3 |
| glowingblue-gamification-levels | 0.1.11           | 752d56d73622c56618701ec24f0150108f57780a |
| glowingblue-keep-search-text    | 0.1.1            | ee6b9e6a2d218903e8ad2132e8c1c7a81df55f26 |
| glowingblue-reverse-proxy-ip    | v0.1.0           | bdc18678fce617ff90a5e3591031e37146b0082b |
| fof-ban-ips                     | 0.2.0            |                                          |
| fof-disposable-emails           | 0.1.0            |                                          |
| glowingblue-anti-spam           | 0.2.1            | 4433fbbefb0acb29a84dc2724099b8b79088bd3b |
| fof-sentry                      | 0.5.0            |                                          |
| bokt-redis                      | 0.1.0            |                                          |
| glowingblue-redis-setup         | 0.1.0            | e2641027ef9305416d7158c8440ea5bcdb4cf034 |
| glowingblue-quickline           | 0.4.15           | 43c7f9bd1515aec38177a229fabb4953c4a7d0dc |
| v17development-support          | v1.2.7           |                                          |
| glowingblue-core                | 0.1.2            | 9626d021a98387b60de6b1c43c0fd6a1cb5d76b5 |
| fof-profile-image-crop          | 0.1.2            |                                          |
+---------------------------------+------------------+------------------------------------------+
Base URL: https://community.quickline.ch
Installation path: /opt/flarum
Debug mode: off
luceos commented 3 years ago

posts.number is calculated on php/backend side.

askvortsov1 commented 3 years ago

Is it possible to calculate it throught the database?

tankerkiller125 commented 3 years ago

I think we could do this database side. But It'd require the use of a complex compound query to do I believe, I might be able to take a crack at it if work doesn't get crazy.

askvortsov1 commented 3 years ago

Well it's not just constructing the query, but also making sure that query automatically gets run while saving, and having ALL of that be DB logic (we can't get the value via query and then save it, we have to do it in one step, otherwise there's no point).

luceos commented 3 years ago

There are two options:

Personally I think a trigger makes most sense, for a migration it would require something like this https://stackoverflow.com/a/55023987/717181

askvortsov1 commented 3 years ago

We could also consider https://stackoverflow.com/a/7821630/13019074 as an option. IMO, the less raw statements in migrations, the better.

luceos commented 3 years ago

I don't think locking tables solves it, it will only create larger problems. When tables are locked nothing else can write into it, so instead of a duplicate key exception you will receive a waiting for lock timeout on instances with much activity. Because remember users have to wait on their post to be written to the database.

askvortsov1 commented 3 years ago

IMO, the less raw statements in migrations, the better.

Actually, this isn't a dealbreaker: in the migration, we could check whether the DB is mysql or postgres. Depending on the answer, we could either run one raw statement or the other. It's not ideal, but I don't think eloquent has a tool for creating triggers.

luceos commented 3 years ago

Further research suggests that using triggers or other logic inside the database counters the idea of an orm as an abstraction layer of the database. That makes sense. I'd still be open to using triggers though, it feels like the most reliable and performant solution.

We could also consider not using number, because as far as I can tell it has hardly any use in the frontend. I once tried to figure out for @Bokt whether the impact would be detrimental, but never really found an answer. Or perhaps we can generate the number in the serializer only by counting all previous posts of a discussion (which might be slow), make it a property only required on the frontend and use the Id for backend logic...

tankerkiller125 commented 3 years ago

I would not be against switching to something like GUIDs for IDs if it can be done reasonably easily. In fact using GUIDs is standard practice where I work explicitly to avoid this kind of issue since GUIDs are based on time and randomization basically making it impossible to get two duplicates. (Assuming your using standard GUIDs and not one of the newer special version like the incrementing GUID)

askvortsov1 commented 3 years ago

as far as I can tell it has hardly any use in the frontend

It's used in the URL to navigate to a specific post (goToNumber). I suppose we could also use IDs, but that would make URLs messier. Not sure if we care about that though (there's already confusion from time to time when number doesn't match up).

Discourse seems to use a "number"-like system, might be worth investigating how they do it.

Dropping number would also make merging/splitting discussions much easler.

Or perhaps we can generate the number in the serializer only by counting all previous posts of a discussion (which might be slow), make it a property only required on the frontend and use the Id for backend logic...

This sounds horribly expensive

I would not be against switching to something like GUIDs for IDs

This is a completely orthogonal topic and should be discussed separately.

tankerkiller125 commented 3 years ago

This is a completely orthogonal topic and should be discussed separately.

Ah yes, my bad, I got confused on exactly what this issue was fixing. Now that I look deeper my thoughts are unrelated.

luceos commented 3 years ago

Having researched a bit about trigger scalability and performance the general consensus seems to be that they are okay ish if you do not use queries that hit/read many rows. As a trigger to update the number on a one million post discussion would do a count on all those rows I fear the result would be an increasing amount of table locks.

As such i was considering the following rough ideas

I bet there are more alternatives but let's first let this sink in.

luceos commented 2 years ago

@bartvb pointed me to insertUsing which is part of the Eloquent Query Builder which allows inserting a value based on a query. I'm investigating whether this is something that can be used inside a Model too.

askvortsov1 commented 2 years ago

@BartVB pointed me to insertUsing which is part of the Eloquent Query Builder which allows inserting a value based on a query. I'm investigating whether this is something that can be used inside a Model too.

This is probably going to be the best way to solve this. The major challenge here will be composing insertUsing with insertGetId, which is used when creating new instances of models, so their ID can immediately be updated as part of the save call.

In theory, this shouldn't be too challenging to implement if we create a util class with some helper methods, and test it carefully. I would also break out the functionality into a trait that Post can use for better modularity. That being said, this feels like a generally useful feature for the Laravel community, so I've opened a discussion over at https://github.com/laravel/framework/discussions/39663.

luceos commented 2 years ago

@askvortsov1 what about this solution?

We abstract the logic of number calculation into a new class or callable. That invokable class or callable would then receive the Post as an argument. The default logic would use $post->discussion->post_number_index like before.

An alternative implementation that I'm considering is instead storing the latest number into redis, but if it doesn't exist do one query to retrieve it and set it into redis.

I know that redis also offers a concurrency blocking mechanism that Laravel implements in jobs/scheduled tasks, so that could be another implementation to consider although it would probably require delaying the saving action, eg:

        $redis = get_redis();
        $lock = $redis->lock('calculate-number-discussion-' . $post->discussion_id, 2);

        if ($lock->acquire()) {
            // .. logic

            $lock->release();
        }
BartVB commented 2 years ago

Other options:

But it seems like insertUsing is the proper way to do this.

askvortsov1 commented 2 years ago

I'll try and play around with some code.

askvortsov1 commented 2 years ago

A WIP solution had been started at https://github.com/flarum/framework/pull/3198 prior to the monorepo switch. Overall it seems correct, but there's an odd error when populating the prepared query. I intend to get this fixed for the v1.3 release.

SychO9 commented 2 years ago

Fixed in https://github.com/flarum/framework/pull/3358