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

[5.4] option to add a queue 'prefix' to all tube names #18860

Merged
merged 5 commits into from
Apr 21, 2017
Merged

[5.4] option to add a queue 'prefix' to all tube names #18860

merged 5 commits into from
Apr 21, 2017

Conversation

browner12
Copy link
Contributor

if you have multiple sites on a server that use the same queue driver,
there is no way for your queue worker to distinguish which jobs belong
to its application, and which jobs belong to other applications. one
way around this is to use custom tube names. however this is difficult
to ensure custom naming, and doesn’t offer a consistent way to set
these.

by adding a queue prefix config option, we have one location to set our
value, which gets automatically applied when a job is added to the
queue, and when it is pulled off the queue.

all tests are passing, but I have not added any additional ones for this yet.

I believe this is fully backwards compatible, and will only take effect if the user adds a config variable.

if you have multiple sites on a server that use the same queue driver,
there is no way for your queue worker to distinguish which jobs belong
to its application, and which jobs belong to other applications. one
way around this is to use custom tube names. however this is difficult
to ensure custom naming, and doesn’t offer a consistent way to set
these.

by adding a queue prefix config option, we have one location to set our
value, which gets automatically applied when a job is added to the
queue, and when it is pulled off the queue.
@jhoff
Copy link
Contributor

jhoff commented Apr 19, 2017

This would be really nice to have. You can prefix Cache and Sessions but not Queues.

*/
public function getQueuePrefix()
{
return isset($this->app['config']['queue.prefix']) ? $this->app['config']['queue.prefix'] : null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we do return $this->app['config']['queue.prefix'] ?? null here? IIRC Laravel now requires PHP >= 7, doesn't it? Or is it only on master?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only on master. 5.5 will be PHP 7+, this is targeting 5.4

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yah, i had originally written ?? and then caught myself when I realize I was on 5.4

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return $this->app['config']->get('queue.prefix')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it appears $this->app['config'] returns an array, not an object, resulting in a 'call to member function get() on array' error.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$this->app['config'] must return object. Object of class Illuminate\Config\Repository

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe I have any control over that. I'm using it identically to other places in the file.

Copy link

@evsign evsign Apr 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$this->app['config']->get(''queue.prefix') and $this->app['config']['queue.prefix'] is have identical behavior. And there no need in isset check, because if this key ('queue.prefix') is not exists then default value (null) will be returned.
Part of the config repository code:

class Repository implements ArrayAccess, ConfigContract
{
.....
    /**
     * Get the specified configuration value.
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function get($key, $default = null)
    {
        return Arr::get($this->items, $key, $default);
    }
.....
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what's going on. In an actual application it returns the config repository, but in the test it is returning a simple array. I've made @taylorotwell 's suggested change and updated the tests to use a config Repository rather than just the array.

*
* @return string
*/
public function getQueuePrefix();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing interfaces is a breaking change. I believe this should target 5.5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntzm since the method is in the abstract parent class, all the driver implementations will inherit it, so everything will work fine. do people define implementations that don't extend the abstract class?

on principle I agree with you. some projects seem more lax when adding new methods to the interface. can an owner comment on this?

Is the simple solution to remove it from the contract for 5.4? as I stated no one is required to use the prefix, so we'd be fine without it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the simple solution to remove it from the contract for 5.4? as I stated no one is required to use the prefix, so we'd be fine without it.

Yes it should not be part of the contract in 5.4, and only do so in 5.5. That how it being done before and should remain so.

@@ -148,7 +148,7 @@ public function deleteMessage($queue, $id)
*/
public function getQueue($queue)
{
return $queue ?: $this->default;
return $this->getQueuePrefix().($queue ?: $this->default);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there would be better to create method in parent class, like getQueueName($queue), and call it in all driver classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I'm following you correctly, the problem with moving the getQueue method to the parent is each driver has a different implementation. take a look at the SqsQueue file, as it's the weirdest of them all.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant a little different. I mean create new method like resolveQueueName($queue) and call it in getQueue.

protected function resolveQueueName($queue) : string
{
  return $this->getQueuePrefix() . ($queue ?? $this->default);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i think i'm following you now. correct me if I'm wrong. the code

$this->getQueuePrefix().($queue ?: $this->default)

appears in 3 of the queue drivers, so you're suggesting adding a method in the parent to handle this?

I agree this would work. I don't know if I see a huge benefit adding it. Might just be an additional function/layer that adds to the complexity. I'm gonna leave it as is for now, but try a PR if this gets merged.

@evsign
Copy link

evsign commented Apr 19, 2017

Perhaps, you forgot about the Database queue driver.

@browner12
Copy link
Contributor Author

@evsign the reason I left it off the database driver is because since the queue is in the database, that gives us our separation between different sites on the same server. your sites aren't sharing databases, so there's no chance of crosstalk.

is there another reason you think it would be beneficial in that driver?

@evsign
Copy link

evsign commented Apr 19, 2017

@browner12 User may have separated database for queues for all sites. In any way, i think all drivers should behave as much as possible in the same way.

@browner12
Copy link
Contributor Author

@evsign doesn't the queue driver use a table to store the queues, not a whole separate database?

I guess I'm okay either way here. I'll wait for an owner to comment on this, and then add it if they want it.

@evsign
Copy link

evsign commented Apr 19, 2017

@browner12 separated database with shared table) In case of redis driver you also can create new connection with different database, or just change database for existed one for every application and use it to avoid collisions or misunderstandings, but prefix do the job too)

@tillkruss tillkruss changed the title option to add a queue 'prefix' to all tube names [5.4] option to add a queue 'prefix' to all tube names Apr 19, 2017
@tillkruss
Copy link
Contributor

Why not just use a separate SQL and Redis database for your installations?

it was pointed out to me that we can’t change contracts on 5.4, so
we’ll set it back to the original here.

these 2 methods can be targeted to 5.5, however.
also needed to update the tests to actually use a config repository
rather than just an array, otherwise the tests will fail with a ‘call
to member function get() on array’ message
@laurencei
Copy link
Contributor

laurencei commented Apr 20, 2017

@tillkruss - as a side point - would this fix the redis cluster tube issue that was discussed a few weeks ago - since you could prefix the queue name with {tube} or something?

@tillkruss
Copy link
Contributor

Yeah, it would make that easier.

@laurencei
Copy link
Contributor

My personal opinion is if you are adding a global queue prefix - then it needs to apply to all queue drivers. It seems strange to specifically exclude one. There is no performance overhead to add it to database - so why not do it?

Plus - it is confusing, because your PR on laravel/laravel does not explain to users that it only potentially applies to some queue drivers.

So I like the concept of this PR - but I think it needs to be all or none...

@browner12
Copy link
Contributor Author

it was added to the database driver a couple days ago.

@laurencei
Copy link
Contributor

Ok cool. Sorry - I was just going off the comments discussion.

👍

@taylorotwell taylorotwell merged commit 6640139 into laravel:5.4 Apr 21, 2017
@browner12 browner12 deleted the queue-prefix branch April 21, 2017 16:43
@jaketoolson
Copy link

jaketoolson commented Apr 21, 2017

How is it @GrahamCampbell didn't close this, give it a thumbs down, and never explain his position? It's a great PR/idea, so I expected it not to be approved.

@ntzm
Copy link
Contributor

ntzm commented Apr 22, 2017

Kind of rude for no reason @jaketoolson, he's been much better recently

@it-can
Copy link
Contributor

it-can commented Apr 28, 2017

@browner12 I was using this in the latest laravel 5.4.20 version with beanstalkd, it seems to add the prefix twice... When listing the tubes in beanstalk I see something weird...

without prefix:

portal

with prefix "server1"

server1server1portal

I will add a seperate issue for this

@browner12
Copy link
Contributor Author

browner12 commented Apr 28, 2017 via email

@it-can
Copy link
Contributor

it-can commented Apr 28, 2017

Its already fixed in #18982

@browner12
Copy link
Contributor Author

browner12 commented Apr 28, 2017 via email

@taylorotwell
Copy link
Member

This entire feature needs to be reverted.

@taylorotwell
Copy link
Member

It's still breaking random things, and I would probably implement it entirely differently. We have no tests for it either.

@browner12
Copy link
Contributor Author

sorry guys 🤕 . i'll try and look into this deeper this week.

@GrahamCampbell
Copy link
Member

For the record, I'm 👎 on this feature, even if it did work. Just adds unnecessary complexity for something that isn't really a problem.

@laurencei
Copy link
Contributor

Just to keep this thread as a source in case people come across it later - this was another thing that broke: #18985

@browner12
Copy link
Contributor Author

thanks man, it'll be good to aggregate them here, because there are a lot of things this touches that I wasn't aware of originally.

* @param string $prefix
* @return $this
*/
public function setQueuePrefix($prefix = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@browner12 Why are these not called setPrefix and getPrefix? After all, we're already in a Queue class here...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there was a method on a parent or child class named similarly, so someone suggested it to help reduce ambiguity.

@browner12
Copy link
Contributor Author

@GrahamCampbell can you explain how you would handle this problem then?

projects should be 100% oblivious to every other project that happens to live on the same server as them. with beanstalk there is no way to ensure that different sites use different queue names.

I really wish beanstalk had a concept similar to a 'shard' like elasticsearch, or some other way to keep them separate.

while this technically doesn't make them 100% oblivious to other projects, it (will) provide a consistent entry point, rather that renaming every single queue everywhere

@GrahamCampbell
Copy link
Member

projects should be 100% oblivious to every other project that happens to live on the same server as them. with beanstalk there is no way to ensure that different sites use different queue names.

When using something like redis, you can just give each website it's own database. In fact, redis gives you 8 separate ones by default. You can add them all in the laravel config.

@GrahamCampbell
Copy link
Member

I would imagine beanstalk has a similar concept?

@browner12
Copy link
Contributor Author

browner12 commented Apr 29, 2017 via email

@jhoff
Copy link
Contributor

jhoff commented Apr 30, 2017

The "Redis has 8/16 databases that you can use for each Laravel instance" is not a good argument for not having this feature. Sessions, cache and queues can all use redis, but queue is the only thing that can't be prefixed. Of the three, I would argue that queues gain the most benefit from leveraging redis as well. If someone has multiple low volume instances of Laravel that all use redis then they have to keep track of all of these database ids so each app can be isolated.

Point being that with as flexible and portable as Laravel is across the board with the drivers offered for nearly every aspect of the framework, we shouldn't be shooting ideas and features down, just because there's another way to do it. If people wanna drive multiple application queues from a single redis database, let them do it. It's like saying that Postgres isn't gonna be supported because you can already use Mysql.

That said, it's too bad that this implementation didn't work. We have a real need for it. I look forward to v2 of it coming out with full test coverage and all the kinks worked out. Maybe it's better suited for the next major / minor version so people can kick the tires on it a bit first.

@browner12
Copy link
Contributor Author

I've read through the beanstalkd documentation, and it appears they have the concept of a 'connection', and I'm hoping that's what we're looking for. i've emailed the author of beanstalkd to see if he can shed a little more light on it, and see if it's appropriate for our use.

evalesoftware pushed a commit to evalesoftware/eVALE that referenced this pull request Nov 23, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.