Even sequentially matching all 200 routes will do the job rather quickly, but we usually use structural approach with routers nesting, so your main router will only contain few top-level dispatchers and every request will be served in few hops.
E.g. for the route /admin/users/10/plans/8/preferences we will have following nesting:
class MainRouter extends Router {
...
any("/admin/*") = new AdminRouter
...
}
class AdminRouter extends Router("/admin") {
...
any("/users") = new UsersMgmtRouter
...
}
class UsersMgmtRouter extends Router("/admin/users") {
...
any("/:id/*") = User.findByParam("id")
.map(u => new UserMgmt(u))
.getOrElse(sendError(404))
...
}
class UserMgmt(user: User) extends Router {
prefix = "/admin/users/" + user.id
...
any("/plans/:id/*") = Plan.findByParam("id").filter(_.user == user).map(p => new PlanMgmt(p))
...
}
class PlanMgmt(plan: Plan) extends Router {
val user = plan.user
prefix = "/admin/users/" + user.id + "/plans/" + plan.id
…
get("/preferences/?") = { // render view }
}
This way you not only get super-fast matching, but also clean structural routes and controllers. You'll never spend much time finding out who exactly dispatches your request.
And yes, the exception is thrown -- this is also okay since the performance cost of Scala's `ControlThrowable` is low.
Best regards,
Boris Okunskiy
Thanks for the info, yes all looks good.
Regarding the exception, that is ok as well, exceptions have an overhead
cause they gather the stacktrace but the overall impact should be
minimal for processing http requests. I did a quick test and a loop with
1000 iterations ,each iteration calls a method that throws an exception,
takes 29ms where us if it doesn't throw an exception it takes 5ms. But
29ms/1000 requests per processor is not bad as overhead.
Regards,
Kostas
> �
trait NoStackTrace extends Throwable {
override def fillInStackTrace(): Throwable =
if (NoStackTrace.noSuppression) super.fillInStackTrace()
else this
}
So we use the same control throwable without stacktrace. You should try the same test with this kind of exceptions.
As a matter of fact, Scala itself throws such things, for example, if you use `return` inside anonymous high-order function. I'm pretty sure you can find the same discussion in the group.
Best regards,
Boris Okunskiy
>> …
Unfortunately the exception caused an other issue. Our project is a
Java/spring based and it would be useful to be able to @Autowired stuff.
Since routing needs 1 router instance per request, I tried to wire
routers to be "prototypes", this means that spring will create 1
instance every time I request the router. So far so good, but because a
Router does it's job inside the constructor and throws an exception,
spring was logging the exception and probably rethrowing it (and
magically later on circumflex was catching it and the request was
processed normally). So the request was processed, but for every request
an exception was logged by spring.
Anyway, I had to avoid using spring for instantiating routers. I am
doing "new Router", manually wiring the dependencies.
An alternative for the exception maybe would be i.e. to collect the
valid routes (or the 1 and only valid route and then just skip the rest)
in a stack or so. But anyway I don't know if that would be equivalent to
the way circumflex works right now. Router could contain a "var
Router.validRoute" pointing to the next router and then circumflex could
do Router.validRoute.validRoute... till it finds the last one. I am just
giving an idea knowing that it probably won't work due to a reason or
the other.
Regarding scala's return statement using an exception, yes I am aware of
it, not using it myself as it can cause troubles and also it was never
needed so far. Some code may catch the exception without rethrowing it
and then all short of weird bugs can occur. But I don't think the scala
team had any other option to achieve this functionality.
Best Regards,
Kostas
>>> �
Unfortunately the exception caused an other issue. Our project is a Java/spring based and it would be useful to be able to @Autowired stuff. Since routing needs 1 router instance per request, I tried to wire routers to be "prototypes", this means that spring will create 1 instance every time I request the router. So far so good, but because a Router does it's job inside the constructor and throws an exception, spring was logging the exception and probably rethrowing it (and magically later on circumflex was catching it and the request was processed normally). So the request was processed, but for every request an exception was logged by spring.
Regards,
Kostas
>
> Best regards,
> Boris Okunskiy
>