There are different behaviors that make sense in different circumstances.
USE CASE: Single flow scenario - The user logs in, flows through the application, and then terminates. The simulation is driven by constantUsersPerSec()
In this case, it makes sense to allow the user to finish its flow and let it terminate itself.
USE CASE: Looping flow - In a loop, the user gets the data, and uses it to log in, do its flow, and then loop back. The simulation has a certain number of users.
In this case, it makes sense to terminate when the virtual user gets back to the .feed()
USE CASE: Do something forever - read from the feeder once, then in a loop do some actions using that user.
In this case, what if the tester tries to inject 100 users, but there are only 98 records in the feeder? Then it makes sense to terminate the simulation, in a way. At the same time, using .exitHereIfFailed would be a perfectly viable alternative. The number of active users would only be 98, but at least you would get a test run with 98 users, instead of a test run that dies because you don't have enough data.
IN MY OPINION - and it is only my opinion, of course - I should have the OPTION of continuing the simulation until it naturally terminates.
One way to get what I'm thinking would be to have another feeder behavior. In addition to .random and .circular, there could be a .exitWhenEmpty. So, for example,
.feed( csv( some-file ).exitWhenEmpty )
Then when .feed() tries to read from the feeder, and the feeder is empty, then the virtual user exits rather than terminating the whole simulation.
Thoughts?